Skip to Content
SandboxWalkthrough

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)
  • jq for JSON parsing
  • uuidgen for 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:

  1. Ensure you’re using curl with TLS 1.3 support
  2. Check that your client.pem and client.key files exist and are valid
  3. Verify your eIDAS certificate hasn’t expired
  4. 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_AI or PSP_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

Last updated on