Skip to content
Rafiki
GitHub

Getting Started

Account Servicing Entities provide and maintain payment accounts. In order to make these accounts Interledger-enabled via Rafiki, they need to provide the following endpoints and services:

Furthermore, each payment account managed by the Account Servicing Entity needs to be issued at least one payment pointer in order to be serviced by Rafiki and send or receive Interledger payments.

Quotes / Rates and Fees

Every Interledger payment is preceded with a quote that estimates the costs for transfering value from A to B. The Account Servicing Entity may set fees on top of that for facilitating that transfer. How they structure those fees is completely up to the Account Servicing Entity.

Exchange Rates

For the quoting to be successful, Rafiki needs to be provided with the current exchange rate by the Account Servicing Entity. The Account Servicing Entity needs to expose an endpoint that accepts a GET requests and responds as follows.

Response Body

Variable NameTypeDescription
baseStringasset code represented as ISO 4217 currency code, e.g. USD
ratesObjectObject containing <asset_code : exchange_rate> pairs, e.g. {EUR: 0.8930}
rates.<asset_code>Numberexchange rate given base and <asset_code>

The response status code for a successful request is a 200. The mock-account-servicing-entity includes a minimalistic example.

The backend package requires an environment variable called EXCHANGE_RATES_URL which MUST specify the URL of this endpoint.

Fees

Sending fees can be set on a given asset using the setFee graphql mutation if desired:

Mutation:

mutation SetFee($input: SetFeeInput!) {
  setFee(input: $input) {
    code
    success
    message
    fee {
      id
      assetId
      type
      fixed
      basisPoints
      createdAt
    }
  }
}

Query Variables:

{
  "input": {
    "assetId": "14863f6f-4bda-42ef-8715-bf4762898af8",
    "type": "SENDING",
    "fee": {
      "fixed": 100,
      "basisPoints": 100
    }
  }
}

Example Successful Response

{
  "data": {
    "setFee": {
      "code": "200",
      "success": true,
      "message": "Fee set",
      "fee": {
        "id": "140fd9c0-8f14-4850-9724-102f04d97e69",
        "assetId": "14863f6f-4bda-42ef-8715-bf4762898af8",
        "type": "SENDING",
        "fixed": "100",
        "basisPoints": 100,
        "createdAt": "2023-09-13T14:59:53.435Z"
      }
    }
  }
}

Webhook Events Listener

Rafiki itself does not hold any balances but needs to be funded for outgoing transfers and money needs to be withdrawn for incoming transfers. In order to notify the Account Servicing Entity about those transfer events, they need to expose a webhook endpoint that listens for these events and reacts accordingly.

The endpoint accepts a POST request with

Request Body

Variable NameTypeDescription
idStringevent id
typeEnum: EventType
dataObjectany additional data

EventType

ValueDescription
incoming_payment.createdIncoming payment has been created.
incoming_payment.completedIncoming payment is complete and doesn’t accept any incoming funds anymore.
incoming_payment.expiredIncoming payment is expired and doesn’t accept any incoming funds anymore.
outgoing_payment.createdOutgoing payment was created.
outgoing_payment.completedOutgoing payment is complete.
outgoing_payment.failedOutgoing payment failed.
payment_pointer.not_foundA requested payment pointer was not found
payment_pointer.web_monetizationWeb Monetization payments received via STREAM.
asset.liquidity_lowAsset liquidity has dropped below defined threshold.
peer.liquidity_lowPeer liquidity has dropped below defined threshold.

The Account Servicing Entity’s expected behavior when observing these webhook events is detailed in the Event Handlers documentation.

The backend package requires an environment variable called WEBHOOK_URL which MUST specify this endpoint.

Identity Provider

The Rafiki backend exposes the Open Payments APIs. They are auth-protected using an opinionated version of the Grant Negotiation Authorization Protocol (GNAP). Rafiki comes with a reference implementation of an Open Payments Auth Server—the auth package.

The Open Payments Auth Server requires integration with an Identity Provider to handle user authentication and consent. For more information on how to integrate an Identity Provider with the reference implementation of the Open Payments Auth Server, see the docs in the auth package.

Issuing Payment Pointers

A Payment Pointer is a standardized identifier for a payment account. It can be created using the Admin API. Note that at least one asset has to be created prior to creating the payment pointer since an assetId MUST be provided as input variable on payment pointer creation.

Create Asset

Query:

mutation CreateAsset ($input: CreateAssetInput!) {
  createAsset(input: $input) {
    code
    success
    message
    asset {
      id
      code
      scale
    }
  }
}

Query Variables:

{
  "input": {
    "code": "USD",
    "scale": 2
  }
}

Example Successful Response

{
  "data": {
    "createAsset": {
      "code": "200",
      "success": true,
      "message": "Created Asset",
      "asset": {
        "id": "0ddc0b7d-1822-4213-948e-915dda58850b",
        "code": "USD",
        "scale": 2
      }
    }
  }
}

Create Payment Pointer

Query:

mutation CreatePaymentPointer($input: CreatePaymentPointerInput!) {
  createPaymentPointer(input: $input) {
    code
    success
    message
    paymentPointer {
      id
      createdAt
      publicName
      url
      asset {
        code
        id
        scale
      }
    }
  }
}

Query Variables:

{
  "input": {
    "assetId": "0ddc0b7d-1822-4213-948e-915dda58850b",
    "publicName": "Sarah Marshall",
    "url": "https://example.wallet.com/sarah"
  }
}

Example Successful Response

{
  "data": {
    "createPaymentPointer": {
      "code": "200",
      "success": true,
      "message": "Created payment pointer",
      "paymentPointer": {
        "id": "695e7546-1803-4b45-96b6-6a53f4082018",
        "createdAt": "2023-03-03T09:07:01.107Z",
        "publicName": "Sarah Marshall",
        "url": "https://example.wallet.com/sarah",
        "asset": {
          "id": "0ddc0b7d-1822-4213-948e-915dda58850b",
          "code": "USD",
          "scale": 2
        }
      }
    }
  }
}

The Account Servicing Entity SHOULD store at least the paymentPointer.id in their internal database to be able to reference the account and payment pointer.

Create Payment Pointer Key

In order to use the Open Payments APIs, a payment pointer needs to be associated with at least one private-public-keypair to be able to sign API request. One or multiple public keys are linked to the payment pointer such that third-parties can verify said request signatures. It can be added using the Admin API.

Query:

mutation CreatePaymentPointerKey($input: CreatePaymentPointerKeyInput!) {
  createPaymentPointerKey(input: $input) {
    code
    message
    success
    paymentPointerKey {
      id
      paymentPointerId
      revoked
      jwk {
        alg
        crv
        kid
        kty
        x
      }
      createdAt
    }
  }
}

Query Variables:

{
  "input": {
    "jwk": {
      "kid": "keyid-97a3a431-8ee1-48fc-ac85-70e2f5eba8e5",
      "x": "ubqoInifJ5sssIPPnQR1gVPfmoZnJtPhTkyMXNoJF_8",
      "alg": "EdDSA",
      "kty": "OKP",
      "crv": "Ed25519"
    },
    "paymentPointerId": "695e7546-1803-4b45-96b6-6a53f4082018"
  }
}

Example Successful Response

{
  "data": {
    "createPaymentPointerKey": {
      "code": "200",
      "message": "Added Key To Payment Pointer",
      "success": true,
      "paymentPointerKey": {
        "id": "f2953571-f10c-44eb-ab41-4450a7ad6771",
        "paymentPointerId": "695e7546-1803-4b45-96b6-6a53f4082018",
        "revoked": false,
        "jwk": {
          "alg": "EdDSA",
          "crv": "Ed25519",
          "kid": "keyid-97a3a431-8ee1-48fc-ac85-70e2f5eba8e5",
          "kty": "OKP",
          "x": "ubqoInifJ5sssIPPnQR1gVPfmoZnJtPhTkyMXNoJF_8"
        },
        "createdAt": "2023-03-03T09:26:41.424Z"
      }
    }
  }
}