Deposits, Travel Rule data first

When a counterparty institution sends funds to one of your customers, its Travel Rule data usually reaches you before the funds do. Notabene receives the transfer for you, checks the deposit address, receives the sender’s data and runs your policies, and once the sender settles the transfer, you credit your customer.

Most deposits need no call from you: your backend listens to the webhooks and credits the customer. You call Notabene only when it asks you something, in steps 2 to 4.

Before you start

  • An access token, as described in Authentication. The examples use the sandbox base URL.
  • Your customers and their deposit addresses registered with Notabene, as described in Customers and Wallets, so that step 2 never comes up.
  • A webhook endpoint, as described in Webhooks.

1. Receive the transfer

When the sender creates the transfer, your webhook endpoint receives transfer.created.v3, with direction set to Incoming. The ref belongs to the sender, so it is empty on your copy.

JSON
{
  "eventType": "transfer.created.v3",
  "payload": {
    "id": "8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80",
    "for": "did:web:beneficiary.example:pt",
    "from": "did:web:originator.example:pt",
    "direction": "Incoming",
    "counterparty": "did:web:originator.example:pt",
    "asset": "eip155:1/slip44:60",
    "amount": "0.5",
    "ref": ""
  }
}
{
  "eventType": "transfer.created.v3",
  "payload": {
    "id": "8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80",
    "for": "did:web:beneficiary.example:pt",
    "from": "did:web:originator.example:pt",
    "direction": "Incoming",
    "counterparty": "did:web:originator.example:pt",
    "asset": "eip155:1/slip44:60",
    "amount": "0.5",
    "ref": ""
  }
}

Read the transfer with include_ivms=true to see the sender’s personal data, which appears under originator.ivms once the deposit address is confirmed. Until then, originator holds only an id, and requires_action is true while something waits on you.

API reference
curl --get https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80 \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --data-urlencode 'include_ivms=true'const url = new URL('https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80');
url.searchParams.set('include_ivms', 'true');

const response = await fetch(url, {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
  },
});
const answer = response.status === 204 ? null : await response.json();import requests

response = requests.get(
    'https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    params={
      "include_ivms": "true"
    },
)
answer = None if response.status_code == 204 else response.json()
What to replace
  • 8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80: The transfer’s id, from the webhook
Response200
{
  "id": "8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80",
  "status": "Active",
  "direction": "Incoming",
  "counterparty": "did:web:originator.example:pt",
  "asset": "eip155:1/slip44:60",
  "amount": "0.5",
  "requires_action": true,
  "originator": {
    "id": "urn:uuid:c4eaf254-57e0-49f2-b10a-985f497eb389",
    "ivms": {
      "naturalPerson": {
        "name": {
          "nameIdentifier": [
            {
              "primaryIdentifier": "Silva",
              "secondaryIdentifier": "Ana",
              "naturalPersonNameIdentifierType": "LEGL"
            }
          ]
        }
      }
    }
  },
  "beneficiary": {
    "id": "urn:uuid:e7d14b39-8a2c-4f05-b6e1-2c9f7a3d5b18"
  }
}
curl --get https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80 \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --data-urlencode 'include_ivms=true'
const url = new URL('https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80');
url.searchParams.set('include_ivms', 'true');

const response = await fetch(url, {
  method: 'GET',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
  },
});
const answer = response.status === 204 ? null : await response.json();
import requests

response = requests.get(
    'https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    params={
      "include_ivms": "true"
    },
)
answer = None if response.status_code == 204 else response.json()
{
  "id": "8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80",
  "status": "Active",
  "direction": "Incoming",
  "counterparty": "did:web:originator.example:pt",
  "asset": "eip155:1/slip44:60",
  "amount": "0.5",
  "requires_action": true,
  "originator": {
    "id": "urn:uuid:c4eaf254-57e0-49f2-b10a-985f497eb389",
    "ivms": {
      "naturalPerson": {
        "name": {
          "nameIdentifier": [
            {
              "primaryIdentifier": "Silva",
              "secondaryIdentifier": "Ana",
              "naturalPersonNameIdentifierType": "LEGL"
            }
          ]
        }
      }
    }
  },
  "beneficiary": {
    "id": "urn:uuid:e7d14b39-8a2c-4f05-b6e1-2c9f7a3d5b18"
  }
}

A transfer only reaches you once the sending institution’s policies have approved it. If the sender never sends its data, the requirement to receive it is skipped after 1 minute, and the skip is recorded in your audit trail.

2. If Notabene cannot match the address, register it

When Notabene cannot match the address, it sends requirements.pending.v3 with a WalletAddressConfirmation requirement whose agentId is your DID. The sender keeps its personal data until the address is confirmed.

Register the address with the customer it belongs to, and Notabene confirms it by itself within seconds, on this transfer and on any other open transfer to it. If the address is not yours, reject it instead.

curl https://sandbox.notabene.id/api/v1/wallets \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "address": "eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
    "customer_id": "urn:uuid:3c9a7e52-41f6-4b8d-a0e2-6d1f9b4c8a27"
  }'const response = await fetch('https://sandbox.notabene.id/api/v1/wallets', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "address": "eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
    "customer_id": "urn:uuid:3c9a7e52-41f6-4b8d-a0e2-6d1f9b4c8a27"
  }),
});
const answer = response.status === 204 ? null : await response.json();import requests

response = requests.post(
    'https://sandbox.notabene.id/api/v1/wallets',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    json={
      "address": "eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
      "customer_id": "urn:uuid:3c9a7e52-41f6-4b8d-a0e2-6d1f9b4c8a27"
    },
)
answer = None if response.status_code == 204 else response.json()
curl https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/wallet-address-confirmation/resolve \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "outcome": "rejected"
  }'const response = await fetch('https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/wallet-address-confirmation/resolve', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "outcome": "rejected"
  }),
});
const answer = response.status === 204 ? null : await response.json();import requests

response = requests.post(
    'https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/wallet-address-confirmation/resolve',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    json={
      "outcome": "rejected"
    },
)
answer = None if response.status_code == 204 else response.json()
What to replace
  • eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed: The deposit address, as CAIP-10
  • urn:uuid:3c9a7e52-41f6-4b8d-a0e2-6d1f9b4c8a27: The id of your customer who owns the address
  • 8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80: The transfer’s id, from the webhook
Response201
{
  "id": "did:pkh:eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
  "address": "eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
  "chain": "eip155:1",
  "customer_id": "urn:uuid:3c9a7e52-41f6-4b8d-a0e2-6d1f9b4c8a27",
  "created_at": "2026-10-20T09:14:03Z"
}
Response204
HTTP/1.1 204 No Content
curl https://sandbox.notabene.id/api/v1/wallets \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "address": "eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
    "customer_id": "urn:uuid:3c9a7e52-41f6-4b8d-a0e2-6d1f9b4c8a27"
  }'
const response = await fetch('https://sandbox.notabene.id/api/v1/wallets', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "address": "eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
    "customer_id": "urn:uuid:3c9a7e52-41f6-4b8d-a0e2-6d1f9b4c8a27"
  }),
});
const answer = response.status === 204 ? null : await response.json();
import requests

response = requests.post(
    'https://sandbox.notabene.id/api/v1/wallets',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    json={
      "address": "eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
      "customer_id": "urn:uuid:3c9a7e52-41f6-4b8d-a0e2-6d1f9b4c8a27"
    },
)
answer = None if response.status_code == 204 else response.json()
{
  "id": "did:pkh:eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
  "address": "eip155:1:0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
  "chain": "eip155:1",
  "customer_id": "urn:uuid:3c9a7e52-41f6-4b8d-a0e2-6d1f9b4c8a27",
  "created_at": "2026-10-20T09:14:03Z"
}
curl https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/wallet-address-confirmation/resolve \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "outcome": "rejected"
  }'
const response = await fetch('https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/wallet-address-confirmation/resolve', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "outcome": "rejected"
  }),
});
const answer = response.status === 204 ? null : await response.json();
import requests

response = requests.post(
    'https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/wallet-address-confirmation/resolve',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    json={
      "outcome": "rejected"
    },
)
answer = None if response.status_code == 204 else response.json()
HTTP/1.1 204 No Content

Rejecting the address answers 204 and rejects the transfer. The sender is told that the address is not yours, so it stops treating it as yours.

3. If you match names, report the result

If you turned on beneficiary name matching, in the dashboard under Authorization Rules › Requirements, compare the beneficiary’s name with your customer’s once the sender’s data has arrived. Reporting the result answers 204.

API reference
curl https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/beneficiary-name-match/resolve \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "outcome": "matched"
  }'const response = await fetch('https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/beneficiary-name-match/resolve', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "outcome": "matched"
  }),
});
const answer = response.status === 204 ? null : await response.json();import requests

response = requests.post(
    'https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/beneficiary-name-match/resolve',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    json={
      "outcome": "matched"
    },
)
answer = None if response.status_code == 204 else response.json()
What to replace
  • 8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80: The transfer’s id, from the webhook
  • matched: matched, partial_match or mismatch
Response204
HTTP/1.1 204 No Content
curl https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/beneficiary-name-match/resolve \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "outcome": "matched"
  }'
const response = await fetch('https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/beneficiary-name-match/resolve', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "outcome": "matched"
  }),
});
const answer = response.status === 204 ? null : await response.json();
import requests

response = requests.post(
    'https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/requirements/beneficiary-name-match/resolve',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    json={
      "outcome": "matched"
    },
)
answer = None if response.status_code == 204 else response.json()
HTTP/1.1 204 No Content
OutcomeWhat happens
matchedThe check is satisfied, and your side goes on to your policies.
partial_matchThe transfer is held for a person on your team to review.
mismatchYour side rejects the transfer.
OutcomeWhat happens
matchedThe check is satisfied, and your side goes on to your policies.
partial_matchThe transfer is held for a person on your team to review.
mismatchYour side rejects the transfer.

4. If your policies flag it, review the transfer

When your policies approve the transfer and nothing else is open on your side, your side is authorized automatically. When they flag it, a person on your team approves or rejects it, in the dashboard under Inbox › Transactions, or through the API.

curl https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/force-authorize \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "reason": "Reviewed by compliance"
  }'const response = await fetch('https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/force-authorize', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "reason": "Reviewed by compliance"
  }),
});
const answer = response.status === 204 ? null : await response.json();import requests

response = requests.post(
    'https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/force-authorize',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    json={
      "reason": "Reviewed by compliance"
    },
)
answer = None if response.status_code == 204 else response.json()
curl https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/reject \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "reason": "Beneficiary account closed"
  }'const response = await fetch('https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/reject', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "reason": "Beneficiary account closed"
  }),
});
const answer = response.status === 204 ? null : await response.json();import requests

response = requests.post(
    'https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/reject',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    json={
      "reason": "Beneficiary account closed"
    },
)
answer = None if response.status_code == 204 else response.json()
What to replace
  • 8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80: The transfer’s id, from the webhook
  • Reviewed by compliance: Why your team approves it, kept on the transfer’s timeline
  • Beneficiary account closed: Why your team rejects it, shared with the sender
Reject response200
{
  "id": "8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80",
  "status": "Rejected",
  "direction": "Incoming",
  "counterparty": "did:web:originator.example:pt"
}
curl https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/force-authorize \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "reason": "Reviewed by compliance"
  }'
const response = await fetch('https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/force-authorize', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "reason": "Reviewed by compliance"
  }),
});
const answer = response.status === 204 ? null : await response.json();
import requests

response = requests.post(
    'https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/force-authorize',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    json={
      "reason": "Reviewed by compliance"
    },
)
answer = None if response.status_code == 204 else response.json()
curl https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/reject \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "reason": "Beneficiary account closed"
  }'
const response = await fetch('https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/reject', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "reason": "Beneficiary account closed"
  }),
});
const answer = response.status === 204 ? null : await response.json();
import requests

response = requests.post(
    'https://sandbox.notabene.id/api/v1/transfers/8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80/reject',
    headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
    json={
      "reason": "Beneficiary account closed"
    },
)
answer = None if response.status_code == 204 else response.json()
{
  "id": "8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80",
  "status": "Rejected",
  "direction": "Incoming",
  "counterparty": "did:web:originator.example:pt"
}

Both calls answer as they do on Withdrawals, and a rejection tells the sender your reason.

Until you change your general default, which is set in Policies, a new account sends every deposit to review as well.

5. Credit your customer

The sender broadcasts the funds and records the transaction hash, so you do not record it yourself. Your webhook endpoint then receives transfer.status_changed.v3 with toStatus set to Settled and the hash in settlementId. Like every event, it can repeat or arrive out of order, so handle it as described in Webhooks.

JSON
{
  "eventType": "transfer.status_changed.v3",
  "payload": {
    "id": "8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80",
    "for": "did:web:beneficiary.example:pt",
    "fromStatus": "ReadyToSettle",
    "toStatus": "Settled",
    "settlementId": "eip155:1:tx/0x7d3c9e1f0a2b4c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d"
  }
}
{
  "eventType": "transfer.status_changed.v3",
  "payload": {
    "id": "8f3c2a1e-5b7d-4c90-a1f2-3e4d5c6b7a80",
    "for": "did:web:beneficiary.example:pt",
    "fromStatus": "ReadyToSettle",
    "toStatus": "Settled",
    "settlementId": "eip155:1:tx/0x7d3c9e1f0a2b4c6d8e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d"
  }
}

Check the hash against the deposit your wallet received, then credit your customer. If the sender records the hash before your side is authorized, the status reads SettledIncompleteAuthorization until it is.

If your wallet receives a deposit that no transfer explains, it came without Travel Rule data, as described in Deposits, funds first.

When a call fails

AnswerWhat it means
400 with expected required property reason to be presentApproving needs a reason.
400 with cannot force-authorize a concluded txThe transfer is already Settled or Rejected.
401The token is missing, malformed or expired. Authentication explains how to get a new one.
409 on approveThe transfer’s compliance inputs changed while it was being approved. Send the request again.
AnswerWhat it means
400 with expected required property reason to be presentApproving needs a reason.
400 with cannot force-authorize a concluded txThe transfer is already Settled or Rejected.
401The token is missing, malformed or expired. Authentication explains how to get a new one.
409 on approveThe transfer’s compliance inputs changed while it was being approved. Send the request again.

Common mistakes

MistakeWhat happensInstead
Reading the sender’s data before the address is confirmedThe originator and the beneficiary carry no personal data yet, since the sender sends it only once your institution has confirmed the address.Register the address in step 2, then read the transfer.
Reading the transfer without include_ivms=trueThe originator and the beneficiary come with their ids only.Add include_ivms=true when you need their personal data.
Rejecting the address to reject the transferThe sender also learns that the address is not yours, and stops treating it as yours.Reject the address only when it is not your customer’s. Otherwise reject the transfer.
MistakeWhat happensInstead
Reading the sender’s data before the address is confirmedThe originator and the beneficiary carry no personal data yet, since the sender sends it only once your institution has confirmed the address.Register the address in step 2, then read the transfer.
Reading the transfer without include_ivms=trueThe originator and the beneficiary come with their ids only.Add include_ivms=true when you need their personal data.
Rejecting the address to reject the transferThe sender also learns that the address is not yours, and stops treating it as yours.Reject the address only when it is not your customer’s. Otherwise reject the transfer.

How it works

Automatic
Manual review
Steps
Automatic
Manual review

Done by Notabene

On the counterparty’s side

Only when needed

← → the step before and after · Esc all steps
Step 1
1A transfer arrives for your customer
Notabene, to your webhook endpoint

A counterparty institution creates a transfer to the address of one of your customers, and your webhook endpoint is told. The event and the call that reads the transfer are in 1. Receive the transfer.

← → the step before and after · Esc all steps
Step
Notabene checks the address and the data
Notabene, as the transfer arrives

Notabene checks that the deposit address belongs to you, receives the sender’s personal data once the address is confirmed, and runs your policies on the transfer.

Good to know
  • When you registered the address, or confirmed it on an earlier transfer, Notabene confirms it by itself.
  • If the sender never sends its data, the requirement to receive it is skipped after its time-out and the skip is recorded in your audit trail. The time-out is 1 minute with either requirements preset.
← → the step before and after · Esc all steps
Only when needed
Register the deposit address
Your backend

Only when Notabene cannot match the address to you. Registering it with its customer confirms it, and rejecting it tells the sender it is not yours. The calls are in 2. If Notabene cannot match the address, register it.

← → the step before and after · Esc all steps
Only when needed
Report the name check
Your backend or your team

Only if you turned on beneficiary name matching, which works with either requirements preset. The call and its answers are in 3. If you match names, report the result.

← → the step before and after · Esc all steps
Automatic
Your policies approve it automatically
Your policy engine, with the rules you configured

When the rules you configured approve the transfer and nothing else is open on your side, your side is authorized automatically, and there is no call to make.

← → the step before and after · Esc all steps
Manual review · Step 4
4Your team reviews a flagged transfer
Your compliance team

When your policies flag the transfer, a person on your team approves or rejects it, in the dashboard under Inbox › Transactions, or through the API. The calls are in 4. If your policies flag it, review the transfer.

Good to know
  • Rejecting tells the sending institution, with your reason.
← → the step before and after · Esc all steps
Step
The sender settles the transfer
The sending institution, in its own systems

The sending institution broadcasts the funds on chain and records the transaction hash on the transfer. Your copy of the transfer follows.

Good to know
  • You do not record the settlement yourself: the sender does.
← → the step before and after · Esc all steps
Step 5
5Credit your customer
Your backend

When the transfer is settled, check the hash against the deposit your wallet received, then credit your customer. The event is in 5. Credit your customer.

← → the step before and after · Esc all steps

Related

  • Transfers: what each institution sees on a transfer, and why statuses differ.
  • Statuses: every status and what your backend does at each.
  • Webhooks: every event and every requirement you may have to answer.
  • Errors: every error message and what to do.

Did this page help you?