Authentication
The MagFi API uses bearer token authentication. You can authenticate using either a short-lived JWT token or a persistent API key.
Choosing an Authentication Method
| Use Case | Method | Token Lifespan |
|---|---|---|
| Server-to-server integrations | API Key | Permanent (until revoked) |
| User-facing applications | JWT Token | 1 hour |
| Testing & development | Either | - |
Environment Setup
All code examples in this guide use a BASE_URL variable. Set this to your target environment:
- Production:
https://api.magfi.net - Sandbox:
https://api.sandbox.magfi.dev
JWT Token Authentication
JWT tokens are ideal for user-facing applications where you authenticate as a specific user. Tokens expire after 1 hour.
Steps
- Call
POST /auth/loginwith email and password - Receive a token in the response
- Include token in
Authorization: Bearer <token>header for subsequent requests - Request a new token when the current one expires (after 1 hour)
Example: Login and Get Token
- cURL
- JavaScript
- Python
- Go
- Rust
- Java
- Ruby
BASE_URL="https://api.magfi.net"
# Step 1: Login to get JWT token
curl -X POST $BASE_URL/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "your-password"
}'
# Response:
# {
# "token": "<your-jwt-token>"
# }
const BASE_URL = "https://api.magfi.net";
// Step 1: Login to get JWT token
async function login(email, password) {
try {
const response = await fetch(`${BASE_URL}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
password: password,
}),
});
if (!response.ok) {
throw new Error(`Login failed: ${response.status}`);
}
const data = await response.json();
return data.token;
} catch (error) {
console.error('Login error:', error);
throw error;
}
}
// Usage
const token = await login('[email protected]', 'your-password');
console.log('JWT Token:', token);
import requests
BASE_URL = "https://api.magfi.net"
# Step 1: Login to get JWT token
def login(email, password):
try:
response = requests.post(
f"{BASE_URL}/auth/login",
json={
"email": email,
"password": password
}
)
response.raise_for_status()
return response.json()["token"]
except requests.exceptions.RequestException as e:
print(f"Login error: {e}")
raise
# Usage
token = login("[email protected]", "your-password")
print(f"JWT Token: {token}")
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
const BASE_URL = "https://api.magfi.net"
type LoginRequest struct {
Email string `json:"email"`
Password string `json:"password"`
}
type LoginResponse struct {
Token string `json:"token"`
}
// Step 1: Login to get JWT token
func login(email, password string) (string, error) {
loginReq := LoginRequest{
Email: email,
Password: password,
}
jsonData, err := json.Marshal(loginReq)
if err != nil {
return "", fmt.Errorf("error marshaling request: %w", err)
}
resp, err := http.Post(
BASE_URL+"/auth/login",
"application/json",
bytes.NewBuffer(jsonData),
)
if err != nil {
return "", fmt.Errorf("login request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("login failed with status: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("error reading response: %w", err)
}
var loginResp LoginResponse
if err := json.Unmarshal(body, &loginResp); err != nil {
return "", fmt.Errorf("error parsing response: %w", err)
}
return loginResp.Token, nil
}
// Usage
func main() {
token, err := login("[email protected]", "your-password")
if err != nil {
fmt.Printf("Login error: %v\n", err)
return
}
fmt.Printf("JWT Token: %s\n", token)
}
use serde::{Deserialize, Serialize};
use reqwest;
const BASE_URL: &str = "https://api.magfi.net";
#[derive(Serialize)]
struct LoginRequest {
email: String,
password: String,
}
#[derive(Deserialize)]
struct LoginResponse {
token: String,
}
// Step 1: Login to get JWT token
async fn login(email: &str, password: &str) -> Result<String, Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let login_req = LoginRequest {
email: email.to_string(),
password: password.to_string(),
};
let response = client
.post(&format!("{}/auth/login", BASE_URL))
.json(&login_req)
.send()
.await?;
if !response.status().is_success() {
return Err(format!("Login failed with status: {}", response.status()).into());
}
let login_resp: LoginResponse = response.json().await?;
Ok(login_resp.token)
}
// Usage
#[tokio::main]
async fn main() {
match login("[email protected]", "your-password").await {
Ok(token) => println!("JWT Token: {}", token),
Err(e) => eprintln!("Login error: {}", e),
}
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.google.gson.Gson;
public class MagFiAuth {
private static final String BASE_URL = "https://api.magfi.net";
private static final Gson gson = new Gson();
static class LoginRequest {
String email;
String password;
LoginRequest(String email, String password) {
this.email = email;
this.password = password;
}
}
static class LoginResponse {
String token;
}
// Step 1: Login to get JWT token
public static String login(String email, String password) throws Exception {
HttpClient client = HttpClient.newHttpClient();
LoginRequest loginReq = new LoginRequest(email, password);
String requestBody = gson.toJson(loginReq);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/auth/login"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
throw new Exception("Login failed with status: " + response.statusCode());
}
LoginResponse loginResp = gson.fromJson(response.body(), LoginResponse.class);
return loginResp.token;
}
// Usage
public static void main(String[] args) {
try {
String token = login("[email protected]", "your-password");
System.out.println("JWT Token: " + token);
} catch (Exception e) {
System.err.println("Login error: " + e.getMessage());
}
}
}
require 'net/http'
require 'json'
require 'uri'
BASE_URL = 'https://api.magfi.net'
# Step 1: Login to get JWT token
def login(email, password)
uri = URI("#{BASE_URL}/auth/login")
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = {
email: email,
password: password
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
unless response.is_a?(Net::HTTPSuccess)
raise "Login failed with status: #{response.code}"
end
data = JSON.parse(response.body)
data['token']
rescue StandardError => e
puts "Login error: #{e.message}"
raise
end
# Usage
token = login('[email protected]', 'your-password')
puts "JWT Token: #{token}"
Example: Using the JWT Token
- cURL
- JavaScript
- Python
- Go
- Rust
- Java
- Ruby
# Step 2: Use the JWT token in subsequent requests
TOKEN="<your-jwt-token>"
curl -X GET $BASE_URL/accounts \
-H "Authorization: Bearer $TOKEN"
// Step 2: Use the JWT token in subsequent requests
async function getAccounts(token) {
try {
const response = await fetch(`${BASE_URL}/accounts`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const accounts = await response.json();
return accounts;
} catch (error) {
console.error('Request error:', error);
throw error;
}
}
// Usage
const accounts = await getAccounts(token);
console.log('Accounts:', accounts);
# Step 2: Use the JWT token in subsequent requests
def get_accounts(token):
try:
response = requests.get(
f"{BASE_URL}/accounts",
headers={"Authorization": f"Bearer {token}"}
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Request error: {e}")
raise
# Usage
accounts = get_accounts(token)
print(f"Accounts: {accounts}")
// Step 2: Use the JWT token in subsequent requests
func getAccounts(token string) ([]byte, error) {
req, err := http.NewRequest("GET", BASE_URL+"/accounts", nil)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("request failed with status: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response: %w", err)
}
return body, nil
}
// Usage
accounts, err := getAccounts(token)
if err != nil {
fmt.Printf("Request error: %v\n", err)
return
}
fmt.Printf("Accounts: %s\n", accounts)
// Step 2: Use the JWT token in subsequent requests
async fn get_accounts(token: &str) -> Result<String, Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let response = client
.get(&format!("{}/accounts", BASE_URL))
.header("Authorization", format!("Bearer {}", token))
.send()
.await?;
if !response.status().is_success() {
return Err(format!("Request failed with status: {}", response.status()).into());
}
let body = response.text().await?;
Ok(body)
}
// Usage
match get_accounts(&token).await {
Ok(accounts) => println!("Accounts: {}", accounts),
Err(e) => eprintln!("Request error: {}", e),
}
// Step 2: Use the JWT token in subsequent requests
public static String getAccounts(String token) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/accounts"))
.header("Authorization", "Bearer " + token)
.GET()
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
throw new Exception("Request failed with status: " + response.statusCode());
}
return response.body();
}
// Usage
String accounts = getAccounts(token);
System.out.println("Accounts: " + accounts);
# Step 2: Use the JWT token in subsequent requests
def get_accounts(token)
uri = URI("#{BASE_URL}/accounts")
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{token}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
unless response.is_a?(Net::HTTPSuccess)
raise "Request failed with status: #{response.code}"
end
JSON.parse(response.body)
rescue StandardError => e
puts "Request error: #{e.message}"
raise
end
# Usage
accounts = get_accounts(token)
puts "Accounts: #{accounts}"
See also: POST /auth/login | POST /auth/logout
API Key Authentication
API keys are ideal for server-to-server integrations and persistent access without user interaction. API keys do not expire unless revoked.
Steps
- Authenticate with a JWT token first (required to create API keys)
- Call
POST /auth/api-keywith your JWT bearer token - Save the returned API key immediately - it's only shown once!
- Use the API key in
Authorization: Bearer <api-key>header for all future requests
Example: Create an API Key
- cURL
- JavaScript
- Python
- Go
- Rust
- Java
- Ruby
# Step 1: Create an API key (requires JWT token)
JWT_TOKEN="<your-jwt-token>"
curl -X POST $BASE_URL/auth/api-key \
-H "Authorization: Bearer $JWT_TOKEN"
# Response:
# {
# "id": "550e8400-e29b-41d4-a716-446655440000",
# "apiKey": "magfi_YOUR_API_KEY_HERE"
# }
#
# ⚠️ IMPORTANT: Save this API key now - it will not be shown again!
// Step 1: Create an API key (requires JWT token)
async function createApiKey(jwtToken) {
try {
const response = await fetch(`${BASE_URL}/auth/api-key`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${jwtToken}`,
},
});
if (!response.ok) {
throw new Error(`Failed to create API key: ${response.status}`);
}
const data = await response.json();
// ⚠️ IMPORTANT: Save this API key now - it will not be shown again!
console.log('API Key ID:', data.id);
console.log('API Key:', data.apiKey);
return data.apiKey;
} catch (error) {
console.error('Error creating API key:', error);
throw error;
}
}
// Usage
const apiKey = await createApiKey(jwtToken);
// Store apiKey in secure environment variable
# Step 1: Create an API key (requires JWT token)
def create_api_key(jwt_token):
try:
response = requests.post(
f"{BASE_URL}/auth/api-key",
headers={"Authorization": f"Bearer {jwt_token}"}
)
response.raise_for_status()
data = response.json()
# ⚠️ IMPORTANT: Save this API key now - it will not be shown again!
print(f"API Key ID: {data['id']}")
print(f"API Key: {data['apiKey']}")
return data['apiKey']
except requests.exceptions.RequestException as e:
print(f"Error creating API key: {e}")
raise
# Usage
api_key = create_api_key(jwt_token)
# Store api_key in secure environment variable
type ApiKeyResponse struct {
ID string `json:"id"`
ApiKey string `json:"apiKey"`
}
// Step 1: Create an API key (requires JWT token)
func createApiKey(jwtToken string) (string, error) {
req, err := http.NewRequest("POST", BASE_URL+"/auth/api-key", nil)
if err != nil {
return "", fmt.Errorf("error creating request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+jwtToken)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusCreated {
return "", fmt.Errorf("failed to create API key with status: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("error reading response: %w", err)
}
var apiKeyResp ApiKeyResponse
if err := json.Unmarshal(body, &apiKeyResp); err != nil {
return "", fmt.Errorf("error parsing response: %w", err)
}
// ⚠️ IMPORTANT: Save this API key now - it will not be shown again!
fmt.Printf("API Key ID: %s\n", apiKeyResp.ID)
fmt.Printf("API Key: %s\n", apiKeyResp.ApiKey)
return apiKeyResp.ApiKey, nil
}
// Usage
apiKey, err := createApiKey(jwtToken)
if err != nil {
fmt.Printf("Error creating API key: %v\n", err)
return
}
// Store apiKey in secure environment variable
#[derive(Deserialize)]
struct ApiKeyResponse {
id: String,
#[serde(rename = "apiKey")]
api_key: String,
}
// Step 1: Create an API key (requires JWT token)
async fn create_api_key(jwt_token: &str) -> Result<String, Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let response = client
.post(&format!("{}/auth/api-key", BASE_URL))
.header("Authorization", format!("Bearer {}", jwt_token))
.send()
.await?;
if !response.status().is_success() {
return Err(format!("Failed to create API key with status: {}", response.status()).into());
}
let api_key_resp: ApiKeyResponse = response.json().await?;
// ⚠️ IMPORTANT: Save this API key now - it will not be shown again!
println!("API Key ID: {}", api_key_resp.id);
println!("API Key: {}", api_key_resp.api_key);
Ok(api_key_resp.api_key)
}
// Usage
match create_api_key(&jwt_token).await {
Ok(api_key) => {
// Store api_key in secure environment variable
},
Err(e) => eprintln!("Error creating API key: {}", e),
}
static class ApiKeyResponse {
String id;
String apiKey;
}
// Step 1: Create an API key (requires JWT token)
public static String createApiKey(String jwtToken) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/auth/api-key"))
.header("Authorization", "Bearer " + jwtToken)
.POST(HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 201) {
throw new Exception("Failed to create API key with status: " + response.statusCode());
}
ApiKeyResponse apiKeyResp = gson.fromJson(response.body(), ApiKeyResponse.class);
// ⚠️ IMPORTANT: Save this API key now - it will not be shown again!
System.out.println("API Key ID: " + apiKeyResp.id);
System.out.println("API Key: " + apiKeyResp.apiKey);
return apiKeyResp.apiKey;
}
// Usage
String apiKey = createApiKey(jwtToken);
// Store apiKey in secure environment variable
# Step 1: Create an API key (requires JWT token)
def create_api_key(jwt_token)
uri = URI("#{BASE_URL}/auth/api-key")
request = Net::HTTP::Post.new(uri)
request['Authorization'] = "Bearer #{jwt_token}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
unless response.code == '201'
raise "Failed to create API key with status: #{response.code}"
end
data = JSON.parse(response.body)
# ⚠️ IMPORTANT: Save this API key now - it will not be shown again!
puts "API Key ID: #{data['id']}"
puts "API Key: #{data['apiKey']}"
data['apiKey']
rescue StandardError => e
puts "Error creating API key: #{e.message}"
raise
end
# Usage
api_key = create_api_key(jwt_token)
# Store api_key in secure environment variable
Example: Using the API Key
- cURL
- JavaScript
- Python
- Go
- Rust
- Java
- Ruby
# Step 2: Use the API key in subsequent requests
API_KEY="magfi_YOUR_API_KEY_HERE"
curl -X GET $BASE_URL/accounts \
-H "Authorization: Bearer $API_KEY"
// Step 2: Use the API key in subsequent requests
const API_KEY = process.env.MAGFI_API_KEY || "magfi_YOUR_API_KEY_HERE";
async function getAccounts() {
try {
const response = await fetch(`${BASE_URL}/accounts`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${API_KEY}`,
},
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}
const accounts = await response.json();
return accounts;
} catch (error) {
console.error('Request error:', error);
throw error;
}
}
import os
# Step 2: Use the API key in subsequent requests
API_KEY = os.getenv('MAGFI_API_KEY', 'magfi_YOUR_API_KEY_HERE')
def get_accounts():
try:
response = requests.get(
f"{BASE_URL}/accounts",
headers={"Authorization": f"Bearer {API_KEY}"}
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Request error: {e}")
raise
import "os"
// Step 2: Use the API key in subsequent requests
func getAccountsWithApiKey() ([]byte, error) {
apiKey := os.Getenv("MAGFI_API_KEY")
if apiKey == "" {
apiKey = "magfi_YOUR_API_KEY_HERE"
}
req, err := http.NewRequest("GET", BASE_URL+"/accounts", nil)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("request failed with status: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response: %w", err)
}
return body, nil
}
use std::env;
// Step 2: Use the API key in subsequent requests
async fn get_accounts_with_api_key() -> Result<String, Box<dyn std::error::Error>> {
let api_key = env::var("MAGFI_API_KEY")
.unwrap_or_else(|_| "magfi_YOUR_API_KEY_HERE".to_string());
let client = reqwest::Client::new();
let response = client
.get(&format!("{}/accounts", BASE_URL))
.header("Authorization", format!("Bearer {}", api_key))
.send()
.await?;
if !response.status().is_success() {
return Err(format!("Request failed with status: {}", response.status()).into());
}
let body = response.text().await?;
Ok(body)
}
// Step 2: Use the API key in subsequent requests
public static String getAccountsWithApiKey() throws Exception {
String apiKey = System.getenv("MAGFI_API_KEY");
if (apiKey == null) {
apiKey = "magfi_YOUR_API_KEY_HERE";
}
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + "/accounts"))
.header("Authorization", "Bearer " + apiKey)
.GET()
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
throw new Exception("Request failed with status: " + response.statusCode());
}
return response.body();
}
# Step 2: Use the API key in subsequent requests
API_KEY = ENV['MAGFI_API_KEY'] || 'magfi_YOUR_API_KEY_HERE'
def get_accounts
uri = URI("#{BASE_URL}/accounts")
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{API_KEY}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
unless response.is_a?(Net::HTTPSuccess)
raise "Request failed with status: #{response.code}"
end
JSON.parse(response.body)
rescue StandardError => e
puts "Request error: #{e.message}"
raise
end
Managing API Keys
List all your API keys: GET /auth/api-key
Delete an API key: DELETE /auth/api-key/:id
See also: POST /auth/api-key
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
401 Unauthorized | Missing or invalid token | Verify token is included in Authorization: Bearer <token> header |
401 Unauthorized | Expired JWT token | JWT tokens expire after 1 hour. Request a new token via /auth/login |
401 Unauthorized | Invalid credentials | Check email/password are correct |
403 Forbidden | Valid token, insufficient permissions | Your account doesn't have access to this resource |
| API key not working | Key was deleted or never saved | API keys are shown only once. If lost, create a new one |
| Network errors | Connection issues or invalid BASE_URL | Verify you're using the correct environment URL (production or sandbox) |
Security Reminders
- 🔒 Store API keys securely - Never commit them to version control. Use environment variables.
- 🔒 Use HTTPS only - The API enforces HTTPS, but ensure your client does too.
- 🔒 Rotate keys regularly - Delete old API keys you're no longer using via
DELETE /auth/api-key/:id.