Quickstart: issue your first IBAN
Issue a virtual IBAN, simulate a transfer to it and receive the webhook, in about ten minutes.
1. Create a sandbox key
Request sandbox access from the contact page. You will receive console access by email. In the console go to Developers → API keys and create a key; it starts with sk_test_. Export it in your shell:
export NEO_API_KEY=sk_test_...
2. Create a collection account
Every account needs a verified holder. In the sandbox, the holder kyb_31QZ is pre-verified for you.
curl https://sandbox.api.neofin.tech/v1/collection-accounts \
-H "Authorization: Bearer $NEO_API_KEY" \
-H "Idempotency-Key: 7f1c2e4a-9b0d-4c55-a1e3-2d6f0b9c8e11" \
-H "Content-Type: application/json" \
-d '{
"currency": "EUR",
"holder": {
"type": "business",
"legal_name": "Helios Merchants B.V.",
"kyb_id": "kyb_31QZ"
},
"external_ref": "mch_8F2K91",
"rules": {
"first_party_only": true,
"max_credit_amount": 5000000
},
"labels": { "region": "NL" }
}'
import { NeoCollect } from "@neofin/collect";
const neo = new NeoCollect(process.env.NEO_API_KEY, { environment: "sandbox" });
const account = await neo.collectionAccounts.create({
currency: "EUR",
holder: { type: "business", legal_name: "Helios Merchants B.V.", kyb_id: "kyb_31QZ" },
external_ref: "mch_8F2K91",
rules: { first_party_only: true },
}, { idempotencyKey: "7f1c2e4a-9b0d-4c55-a1e3-2d6f0b9c8e11" });
console.log(account.iban); // FR7630004012773091526107
from neofin import NeoCollect
neo = NeoCollect(api_key=os.environ["NEO_API_KEY"], environment="sandbox")
account = neo.collection_accounts.create(
currency="EUR",
holder={"type": "business", "legal_name": "Helios Merchants B.V.", "kyb_id": "kyb_31QZ"},
external_ref="mch_8F2K91",
rules={"first_party_only": True},
idempotency_key="7f1c2e4a-9b0d-4c55-a1e3-2d6f0b9c8e11",
)
print(account.iban) # FR7630004012773091526107
The response is synchronous and includes the IBAN:
{
"id": "ca_9Hc2LmQ",
"object": "collection_account",
"status": "active",
"currency": "EUR",
"iban": "FR7630004012773091526107",
"bic": "NEOFFRP1",
"holder": {
"type": "business",
"legal_name": "Helios Merchants B.V.",
"kyb_id": "kyb_31QZ"
},
"external_ref": "mch_8F2K91",
"rules": { "first_party_only": true, "max_credit_amount": 5000000 },
"labels": { "region": "NL" },
"created_at": "2026-11-05T14:02:11Z"
}
3. Register a webhook endpoint
Run a tunnel to your local server (for example ngrok http 3000) and register the public URL. Keep the returned secret; you will use it to verify signatures.
curl https://sandbox.api.neofin.tech/v1/webhook-endpoints \
-H "Authorization: Bearer $NEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://your-tunnel.example/neo/webhooks", "events": ["credit.*"] }'
4. Simulate a credit
In the sandbox you can create an inbound transfer directly. Use the IBAN from step 2.
curl https://sandbox.api.neofin.tech/v1/sandbox/credits \
-H "Authorization: Bearer $NEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"iban": "FR7630004012773091526107",
"amount": 125000,
"currency": "EUR",
"payer_name": "Helios Merchants B.V.",
"payer_iban": "DE89370400440532013000",
"remittance_info": "INV-2291"
}'
5. Receive credit.settled
Within a few seconds your endpoint receives the event. Verify the NEO-Signature header before trusting it (see Verifying signatures).
{
"id": "ev_5Tq81",
"type": "credit.settled",
"created_at": "2026-11-05T14:02:13Z",
"data": {
"id": "cr_2Kd9xZ",
"collection_account": "ca_9Hc2LmQ",
"external_ref": "mch_8F2K91",
"amount": 1240000,
"currency": "EUR",
"rail": "sepa",
"payer": {
"name": "Kestrel Logistics GmbH",
"iban": "DE89 •••• •••• •••• 3000 00",
"country": "DE"
},
"shield": {
"name_match": "exact",
"score": 1.0,
"screening": "clear",
"decision": "accept"
},
"remittance_info": "INV-2291",
"settled_at": "2026-11-05T14:02:13Z"
}
}
6. Fetch the balance
curl https://sandbox.api.neofin.tech/v1/balances/ca_9Hc2LmQ \
-H "Authorization: Bearer $NEO_API_KEY"
{ "account": "ca_9Hc2LmQ", "currency": "EUR", "available": 125000, "held": 0, "in_review": 0 }
7. Simulate a mismatch
Send another credit with "payer_name": "J. Marsh". Because the account has first_party_only: true, Shield returns it and you receive credit.returned:
{
"id": "ev_5Tq94",
"type": "credit.returned",
"created_at": "2026-11-05T15:41:07Z",
"data": {
"id": "cr_7Pq1nW",
"collection_account": "ca_4Rt8KpL",
"external_ref": "mch_2A7D55",
"amount": 480000,
"currency": "EUR",
"rail": "sepa",
"payer": { "name": "J. Marsh", "iban": "FR14 •••• •••• •••• 0606 10", "country": "FR" },
"shield": {
"name_match": "no_match",
"score": 0.08,
"screening": "clear",
"decision": "return"
},
"return_reason": "third_party_funds",
"returned_at": "2026-11-05T15:41:07Z"
}
}