Sandbox Walkthrough
This guide walks you through a complete integration with the Lunar Open Banking sandbox, from registration to making your first API calls.
This walkthrough assumes you have curl, jq, and uuidgen installed on
your system. On macOS, you may need to install curl with OpenSSL support:
brew install curl-openssl
Prerequisites
Before starting, ensure you have:
- A valid eIDAS QWAC certificate from a Qualified Trust Service Provider (QTSP)
- A terminal with TLS 1.3 support
curl(with OpenSSL for TLS 1.3)jqfor JSON parsinguuidgenfor generating request IDs
See the Security model for details on certificate requirements.
Step 1: Register as a TPP
With your eIDAS certificate ready, register as a Third Party Provider to receive client credentials.
# Create a directory for your sandbox files
mkdir -p sandbox-test && cd sandbox-test
# Define your registration payload
# Replace the redirect URI with your actual callback URL
registration_payload=$(cat <<EOF
{
"name": "mycompany",
"roles": ["PSP_AI", "PSP_PI"],
"redirectUris": ["https://localhost:8080/callback"]
}
EOF
)
# Register with the sandbox
curl \
--silent \
--header "Content-Type: application/json" \
--cert client.pem \
--key client.key \
--request POST \
--data "$registration_payload" \
https://tpp.openbanking-sandbox.prod.lunar.tech/tpp | jq .Save the response—you’ll need the clientId and clientSecret for authentication:
{
"clientId": "11111111-2222-3333-4444-555555555555",
"clientSecret": "aBcDeFgHiJkLmNoPqRsTuVwXyZ123456"
}The clientSecret is only returned once. Store it securely—if you lose it,
you’ll need to re-register.
# Store credentials as environment variables for later use
export CLIENT_ID="your-client-id-here"
export CLIENT_SECRET="your-client-secret-here"Step 2: Get a TPP access token
For TPP management operations, obtain an access token using the client credentials grant:
# Base64 encode credentials for Basic auth
AUTH=$(echo -n "${CLIENT_ID}:${CLIENT_SECRET}" | base64)
# Request access token
curl \
--silent \
--header "Authorization: Basic ${AUTH}" \
--header "Content-Type: application/x-www-form-urlencoded" \
--cert client.pem \
--key client.key \
--request POST \
--data "grant_type=client_credentials" \
https://auth.sandbox.openbanking.prod.lunar.app/oauth2/token | jq .Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}Step 3: Start the user authorization flow
To access user account data, you need to initiate an OAuth2 authorization code flow. In a real application, you would redirect the user to this URL:
# Construct the authorization URL
AUTH_URL="https://auth.sandbox.openbanking.prod.lunar.app/oauth2/auth"
REDIRECT_URI="https://localhost:8080/callback"
SCOPES="PSP_AI%20offline"
STATE=$(uuidgen)
echo "Open this URL in a browser:"
echo "${AUTH_URL}?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPES}&state=${STATE}"In sandbox, the consent flow is simulated. Follow the on-screen instructions to complete the authorization. You’ll receive an authorization code in the callback URL.
Step 4: Exchange authorization code for tokens
After the user authorizes access, you’ll receive an authorization code in your redirect URI. Exchange it for access and refresh tokens:
# Replace with the actual code from your callback
AUTHORIZATION_CODE="your-authorization-code"
curl \
--silent \
--header "Authorization: Basic ${AUTH}" \
--header "Content-Type: application/x-www-form-urlencoded" \
--request POST \
--data "grant_type=authorization_code&code=${AUTHORIZATION_CODE}&redirect_uri=${REDIRECT_URI}" \
https://auth.sandbox.openbanking.prod.lunar.app/oauth2/token | jq .Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "xRxGGEpVawiUak6He367W3oeOfh...",
"scope": "PSP_AI offline"
}# Store the access token
export ACCESS_TOKEN="your-access-token-here"Step 5: List user accounts
With a valid access token, you can now access user account information:
curl \
--silent \
--header "Authorization: Bearer ${ACCESS_TOKEN}" \
--header "X-Request-Id: $(uuidgen)" \
https://sandbox.openbanking.prod.lunar.app/accounts | jq .Example response:
{
"accounts": [
{
"id": "acc-12345678-1234-1234-1234-123456789012",
"name": "Main Account",
"currency": "DKK",
"iban": "DK1234567890123456",
"balanceAmount": 10000.0,
"balanceAvailableAmount": 9500.0,
"type": "CHECKING",
"supportsPayments": true,
"supportsTransfers": true,
"ownerName": "Test User"
}
]
}Step 6: Get account transactions
Retrieve transaction history for a specific account:
ACCOUNT_ID="acc-12345678-1234-1234-1234-123456789012"
curl \
--silent \
--header "Authorization: Bearer ${ACCESS_TOKEN}" \
--header "X-Request-Id: $(uuidgen)" \
"https://sandbox.openbanking.prod.lunar.app/accounts/${ACCOUNT_ID}/transactions?limit=10" | jq .Example response:
{
"transactions": [
{
"id": "tx-98765432-1234-1234-1234-123456789012",
"transactionTime": "2024-01-15T10:30:00Z",
"billingAmount": -150.0,
"title": "Coffee Shop",
"type": "card",
"status": "financial"
}
]
}Step 7: Refresh your access token
When your access token expires, use the refresh token to get a new one:
REFRESH_TOKEN="your-refresh-token-here"
curl \
--silent \
--header "Authorization: Basic ${AUTH}" \
--header "Content-Type: application/x-www-form-urlencoded" \
--request POST \
--data "grant_type=refresh_token&refresh_token=${REFRESH_TOKEN}" \
https://auth.sandbox.openbanking.prod.lunar.app/oauth2/token | jq .Troubleshooting
Certificate errors
If you receive TLS or certificate errors:
- Ensure you’re using curl with TLS 1.3 support
- Check that your
client.pemandclient.keyfiles exist and are valid - Verify your eIDAS certificate hasn’t expired
- Ensure your certificate chain is complete (leaf to root)
401 Unauthorized
- Ensure your access token hasn’t expired
- Verify you’re using the correct authorization header format
- Check that your client credentials are correct
403 Forbidden
- Confirm your TPP registration includes the required roles (
PSP_AIorPSP_PI) - Verify your certificate is valid and matches your registration
- Check that the certificate roles match or are a superset of the requested TPP roles
Next steps
- Explore the Accounts API for detailed endpoint documentation
- Learn about Payment Initiation to initiate transfers
- Review the full API Reference for complete specifications
- Learn about Client Management to update redirect URIs or add certificates