Skip to Content
SandboxDrafts & Signing Baskets

Sandbox Drafts & Signing Baskets

The sandbox supports the same staged draft and signing-basket flow as production for Domestic Credit Transfer, SE Bank Giro, and SE Plus Giro drafts, using the same endpoints. For field references, validation rules, error codes, and status vocabulary, see Signing Baskets & Drafts.

This page covers what differs when testing against the sandbox.

Flow

  1. Create a draft (POST /payments/drafts/{payment-type}) — starts in CREATED
  2. Update it via PATCH until isValid is true
  3. Approve it, alone or batched with other drafts, via POST /payments/drafts/approve
  4. Poll GET /payments/drafts/approve/{requestId}/status — or the draft or payment endpoint — until the payment reaches its final status

Approval requires no user interaction

POST /payments/drafts/approve returns status: APPROVED immediately — no Strong Customer Authentication is required. The returned authUrl behaves the same as for direct payments: it leads to a sandbox page that redirects back to your redirectUrl (see Sandbox Payment Flows).

Approval covers only the authorization step — the resulting payment may still take a moment to complete.

Settle timing

Draft typeStatus right after approvalBecomes
Domestic Credit TransferPENDINGCOMPLETED after a few seconds
SE Bank Giro / SE Plus GiroCOMPLETED— (completes on approval)

A domestic credit transfer draft is not finished the moment approval returns. Poll until the status changes, the same as you would in production. Once it settles, the payment also appears as a posted transaction on the sender account.

Timing differs per payment type, so don’t assume uniform behaviour when approving a basket that mixes payment types.

Cancelling before settlement

DELETE /payments/drafts/domestic-credit-transfer/{id}/payment
When calledResult
While the draft is PENDING204 No Content — payment cancelled, draft returns to CREATED
After the draft is COMPLETED409 Conflict — the payment has already settled

To test the cancellation path, send the DELETE right after approving.

Example

DRAFT_ID=$(uuidgen) REQUEST_ID=$(uuidgen) # 1. Create the draft curl \ --silent \ --cert client.pem \ --key client.key \ --header "Authorization: Bearer ${ACCESS_TOKEN}" \ --header "Content-Type: application/json" \ --header "X-Request-Id: $(uuidgen)" \ --request POST \ --data '{ "draftId": "'${DRAFT_ID}'", "name": "Rent May" }' \ https://sandbox.openbanking.prod.lunar.app/aisp-pisp/payments/drafts/domestic-credit-transfer | jq . # 2. Fill in the required fields curl \ --silent \ --cert client.pem \ --key client.key \ --header "Authorization: Bearer ${ACCESS_TOKEN}" \ --header "Content-Type: application/json" \ --header "X-Request-Id: $(uuidgen)" \ --request PATCH \ --data '{ "receiverAccountBban": "12341234567", "receiverName": "Test Receiver", "amount": "150.00", "currency": "DKK", "senderAccountId": "'${ACCOUNT_ID}'" }' \ https://sandbox.openbanking.prod.lunar.app/aisp-pisp/payments/drafts/domestic-credit-transfer/${DRAFT_ID} | jq . # 3. Approve via a signing basket curl \ --silent \ --cert client.pem \ --key client.key \ --header "Authorization: Bearer ${ACCESS_TOKEN}" \ --header "Content-Type: application/json" \ --header "X-Request-Id: $(uuidgen)" \ --request POST \ --data '{ "requestId": "'${REQUEST_ID}'", "draftIds": ["'${DRAFT_ID}'"], "redirectUrl": "https://localhost:8080/callback" }' \ https://sandbox.openbanking.prod.lunar.app/aisp-pisp/payments/drafts/approve | jq . # 4. Poll the approval status — PENDING at first, COMPLETED a few seconds later curl \ --silent \ --cert client.pem \ --key client.key \ --header "Authorization: Bearer ${ACCESS_TOKEN}" \ --header "X-Request-Id: $(uuidgen)" \ https://sandbox.openbanking.prod.lunar.app/aisp-pisp/payments/drafts/approve/${REQUEST_ID}/status | jq .

The status response reports the basket and each draft in it:

{ "status": "APPROVED", "drafts": [{ "draftId": "...", "status": "PENDING", "paymentId": "..." }] }

Differences from production

AspectSandboxProduction
Approval / SCAAuto-approved, no user interactionReal SCA via the Lunar app
Settle timingFixed short delay (DCT) or immediate (SE Giro)Depends on real payment rails
State persistenceIn-memory, ~24h TTLPersistent database storage
Last updated on