Backend service
Rafiki’s backend
service is the software’s main service for handling business logic and external communication. The service is responsible for:
- Exposing the endpoints of the Open Payments APIs for public clients to initiate payments and look up information. This is the external communication piece.
- Exposing an Interledger connector to send and receive STREAM packets with peers.
- Enabling you to manage accounts and track liquidity.
- Exposing an internal GraphQL Backend Admin API for service operators to manage accounts, liquidity, and application settings, like peering relationships.
The following are required when using the backend
service.
OPERATOR_TENANT_ID
(UUID v4) and a strong, randomAPI_SECRET
- Redis database as a cache to share STREAM connection details and total amounts received across processes
- Postgres database, separate from the
auth
service’s database, for Open Payments resources - Create the operator tenant record in the Postgres database with
OPERATOR_TENANT_ID
prior to startup (on startup, the backend syncs the operator’s API secret fromAPI_SECRET
) - TigerBeetle or separate Postgres database for accounting liquidity
On startup, the backend
service seeds/updates the OPERATOR_TENANT_ID
and syncs its API secret from API_SECRET
.
You must also set the environment variables for the backend
service.
The backend
service exposes the Open Payments APIs, which are auth-protected using an opinionated version of the Grant Negotiation and Authorization Protocol (GNAP). Review the auth
service page for more details about grant authorization and authentication.
The backend
service allows you to manage Open Payments incoming payments, quotes, and outgoing payments. Quotes and outgoing payments call the ILP connector, described in the next section, to send ILP packets. Quoting sends unfulfillable probe packets, for example to determine a transaction’s cost before executing the payment. Outgoing payments send packets as part of executing the payment.
The backend
service exposes an ILP connector to send and receive ILP packets between peers.
Some of the responsibilities of a connector include:
- Authenticating packets against ILP account credentials.
- Forwarding packets to a sender or receiver.
- Rejecting a packet for any number of reasons, including expiration, insufficient liquidity, rate limit exceeded, or if the amount exceeds the
maxPacketAmount
agreed to by the connector and its peer. - Converting currencies.
- Fulfilling packets with an internal STREAM server.
The backend
service includes an HTTP server listening on the configured CONNECTOR_PORT
. Your connector can receive incoming packets via HTTP and/or direct calls from within the backend
service. An incoming packet is only accepted if it’s from a configured peer and accompanied by your peer’s incoming HTTP authToken
.
Similarly, if a packet’s destination address corresponds to a peer, your connector forwards the packet to your peer over HTTP, along with your peer’s outgoing HTTP authToken
.
A packet can either continue on to your peer via HTTP or end at your Rafiki instance’s STREAM server. If the packet terminates at your STREAM server, your connector attempts to extract and decode the payment tag from the packet’s destination address. When your connector successfully matches the tag with a locally managed wallet address or incoming payment, the connector does not forward the packet. Instead, it credits the corresponding balance and track the total amount received in Redis to support STREAM receipts. Packets addressed to a wallet address happen via SPSP.
The backend
service exposes a GraphQL Backend Admin API to manage tenants, assets, peers, wallet addresses, Open Payments resources, and several types of liquidity, all within a specific tenant’s context.
To ensure the security and integrity of your Rafiki instance, all requests to the Backend Admin API must include a tenant-id
header and be signed using HMAC SHA-256 with the tenant’s API secret. Include a signature
header containing the request signature and a tenant-id
header identifying the tenant on whose behalf the request is made. Rafiki validates the signature, derives the tenant context from the signed headers, and applies tenant-based access control. The Rafiki Admin application automatically signs requests and includes the tenant-id
header.
Tenants are added to Rafiki through the Backend Admin API or the Rafiki Admin application. The auth
service does not expose a public endpoint to create tenants. Tenant creation in the auth
service is triggered by the backend
service. The operator tenant is identified by the OPERATOR_TENANT_ID
environment variable and secured with the API_SECRET
environment variable. The operator has elevated permissions and can manage resources for all other tenants. The operator can also choose to receive webhook events for all tenants by setting the SEND_TENANT_WEBHOOKS_TO_OPERATOR
environment variable to true
.
Required
Variable | Helm value name | Default | Description |
---|---|---|---|
AUTH_SERVER_GRANT_URL | backend.serviceUrls.AUTH_SERVER_GRANT_URL | undefined | The endpoint on your Open Payments authorization server to grant a request. |
AUTH_SERVER_INTROSPECTION_URL | backend.serviceUrls.AUTH_SERVER_INTROSPECTION_URL | undefined | The endpoint on your Open Payments authorization server to introspect an access token. |
DATABASE_URL | backend.postgresql.host ,backend.postgresql.port ,backend.postgresql.username ,backend.postgresql.database ,backend.postgresql.password | postgresql://postgres:password@localhost:5432/development | The Postgres database URL of the database storing your resource data. For Helm, these components are provided individually. |
EXCHANGE_RATES_URL | backend.serviceUrls.EXCHANGE_RATES_URL | undefined | The default exchange rates endpoint. Used if a tenant-specific rates endpoint isn’t configured. |
ILP_ADDRESS | backend.ilp.address | undefined | The ILP address of your Rafiki instance. |
ILP_CONNECTOR_URL | backend.ilp.connectorUrl | undefined | The ILP connector address where ILP packets are received. |
KEY_ID | backend.key.id | undefined | Your Rafiki instance’s client key ID. |
OPEN_PAYMENTS_URL | backend.serviceUrls.OPEN_PAYMENTS_URL | undefined | The public endpoint of your Open Payments resource server. |
REDIS_URL | backend.redis.host ,backend.redis.port | redis://127.0.0.1:6379 | The Redis URL of the database handling ILP packet data. For Helm, these components are provided individually. |
USE_TIGERBEETLE | backend.use.tigerbeetle | true | When true , a TigerBeetle database is used for accounting. When false , a Postgres database is used. |
WEBHOOK_URL | backend.serviceUrls.WEBHOOK_URL | undefined | The default webhook endpoint. Used if a tenant-specific webhook URL isn’t configured. |
AUTH_SERVICE_API_URL | backend.serviceUrls.AUTH_SERVICE_API_URL | undefined | The service-to-service API endpoint on your Open Payments authorization server. |
OPERATOR_TENANT_ID | undefined | undefined | The unique identifier of the operator. Must be a UUID v4 generated by the operator. |
Conditionally required
Variable | Helm value name | Default | Description |
---|---|---|---|
INSTANCE_NAME | backend.instance.name | undefined | Your Rafiki instance’s name used to communicate for auto-peering and/or telemetry. Required when auto-peering and/or telemetry is enabled |
TRUST_PROXY | backend.trustProxy | false | Must be set to true when running Rafiki behind a proxy. When true , the X-Forwarded-Proto header is used to determine if connections are secure. |
Optional
Variable | Helm value name | Default | Description |
---|---|---|---|
ADMIN_PORT | backend.port.admin | 3001 | The port of your Backend Admin API server. |
ADMIN_API_SIGNATURE_TTL_SECONDS | undefined | 30 | The TTL, in seconds, for which a Backend Admin API request signature is valid. |
API_SECRET | undefined | undefined | Operator API secret used to sign Backend Admin API requests (HMAC SHA‑256). Set to a strong, random value. Synced to the operator tenant on startup. |
API_SIGNATURE_VERSION | undefined | 1 | The version of the HMAC SHA-256 request-signing algorithm used by the Backend Admin API. |
AUTO_PEERING_SERVER_PORT | backend.autoPeering.serverPort | 3005 | If auto-peering is enabled, the server will use this port. |
CONNECTOR_PORT | backend.port.connector | 3002 | The port of the ILP connector for sending packets via ILP over HTTP. |
ENABLE_AUTO_PEERING | backend.enable.autoPeering | false | When true , auto-peering is enabled. |
ENABLE_MANUAL_MIGRATIONS | backend.enableManualMigrations | false | When true , you must run the database manually with the command npm run knex – migrate:latest –env production |
ENABLE_SPSP_PAYMENT_POINTERS | backend.enable.spspPaymentPointers | true | When true , the SPSP route is enabled. |
ENABLE_TELEMETRY | undefined | false | Enables the telemetry service on Rafiki. |
ENABLE_TELEMETRY_TRACES | undefined | false | N/A |
EXCHANGE_RATES_LIFETIME | backend.lifetime.exchangeRate | 15_000 | The time, in milliseconds, the exchange rates you provide via the EXCHANGE_RATES_URL are valid. |
GRAPHQL_IDEMPOTENCY_KEY_LOCK_MS | backend.idempotency.keyLockMs | 2000 | The TTL, in milliseconds, for idempotencyKey concurrency lock on GraphQL mutations on the Backend Admin API. |
GRAPHQL_IDEMPOTENCY_KEY_TTL_MS | backend.idempotency.keyTTL | 86400000 (24 hours) | The TTL, in milliseconds, for idempotencyKey on GraphQL mutations on the Backend Admin API. |
INCOMING_PAYMENT_CREATED_POLL_FREQUENCY_MS | undefined | 1000 | N/A |
INCOMING_PAYMENT_CREATED_POLL_TIMEOUT_MS | undefined | 10000 | N/A |
INCOMING_PAYMENT_EXPIRY_MAX_MS | backend.incomingPayment.expiryMaxMs | 2592000000 (30 days) | The maximum into the future, in milliseconds, incoming payments expiry can be set to on creation. |
INCOMING_PAYMENT_WORKER_IDLE | backend.workerIdle | 200 | The time, in milliseconds, that INCOMING_PAYMENT_WORKERS will wait until checking an empty incoming payment request queue again. |
INCOMING_PAYMENT_WORKERS | backend.workers.incomingPayment | 1 | The number of workers processing incoming payment requests. |
LOG_LEVEL | backend.logLevel | info | Pino log level |
MAX_OUTGOING_PAYMENT_RETRY_ATTEMPTS | undefined | 5 | Specifies how many times an outgoing payment is retried before failing completely |
NODE_ENVIRONMENT | backend.nodeEnv | development | The type of node environment: development , test , or production . |
OPEN_PAYMENTS_PORT | backend.port.openPayments | 3003 | The port of your Open Payments resource server. |
OPEN_TELEMETRY_COLLECTOR_URLS | undefined | *undefined | N/A |
OPEN_TELEMETRY_EXPORT_INTERVAL | undefined | 15000 | N/A |
OPEN_TELEMETRY_TRACE_COLLECTOR_URLS | undefined | undefined | N/A |
OUTGOING_PAYMENT_WORKER_IDLE | backend.workerIdle | 200 | The time, in milliseconds, that OUTGOING_PAYMENT_WORKERS wait until they check an empty outgoing payment request queue again. |
OUTGOING_PAYMENT_WORKERS | backend.workers.outgoingPayment | 4 | The number of workers processing outgoing payment requests. |
POLL_INCOMING_PAYMENT_CREATED_WEBHOOK | undefined | false | N/A |
PRIVATE_KEY_FILE | backend.key.file | undefined | The path to your Rafiki instance’s client private key. |
QUOTE_LIFESPAN | backend.lifetime.quote | 5 * 60_000 (5 minutes) | The time, in milliseconds, an Open Payments quote is valid for. |
REDIS_TLS_CA_FILE_PATH | backend.redis.tlsCaFile | '' | Redis TLS config |
REDIS_TLS_CERT_FILE_PATH | backend.redis.tlsCertFile | '' | Redis TLS config |
REDIS_TLS_KEY_FILE_PATH | backend.redis.tlsKeyFile | '' | Redis TLS config |
SEND_TENANT_WEBHOOKS_TO_OPERATOR | undefined | false | When true , webhook events for non-operator tenants are also sent to the operator. This allows the operator to monitor and manage events across all tenants. |
SIGNATURE_SECRET | backend.quoteSignatureSecret | undefined | The secret to generate request header signatures for webhook event requests. |
SIGNATURE_VERSION | backend.signatureVersion | 1 | The version number to generate request header signatures for webhook events. |
SLIPPAGE | backend.ilp.slippage | 0.01 (1%) | The accepted ILP rate fluctuation. |
STREAM_SECRET | backend.ilp.streamSecret | undefined | The seed secret to generate shared STREAM secrets. |
TELEMETRY_EXCHANGE_RATES_LIFETIME | undefined | 86_400_000 | N/A |
TELEMETRY_EXCHANGE_RATES_URL | undefined | https://telemetry-exchange-rates.s3.amazonaws.com/exchange-rates-usd.json | The endpoint Rafiki will query for exchange rates. Used as a fallback if/when exchange rates aren’t provided. |
TIGERBEETLE_CLUSTER_ID | undefined | 0 | The TigerBeetle cluster ID picked by the system that starts the TigerBeetle cluster to create a TigerBeetle client. |
TIGERBEETLE_REPLICA_ADDRESSES | undefined | 3004 | TigerBeetle replica addresses for all replicas in the cluster. The addresses are comma-separated IP addresses/ports, to create a TigerBeetle client. |
TIGERBEETLE_REPLICA_ADDRESSES.SPLIT | undefined | 3004 | N/A |
TIGERBEETLE_TWO_PHASE_TIMEOUT_SECONDS | undefined | 5 | N/A |
WALLET_ADDRESS_DEACTIVATION_PAYMENT_GRACE_PERIOD_MS | backend.walletAddress.deactivationPaymentGracePeriodMs | 86400000 (24 hours) | The time into the future, in milliseconds, to set expiration of Open Payments incoming payments when deactivating a wallet address. |
WALLET_ADDRESS_LOOKUP_TIMEOUT_MS | backend.walletAddress.lookupTimeoutMs | 1500 | The time, in milliseconds, you have to create a missing wallet address before timeout. |
WALLET_ADDRESS_POLLING_FREQUENCY_MS | backend.walletAddress.pollingFrequencyMs | 100 | The frequency of polling while waiting for you to create a missing wallet address. |
WALLET_ADDRESS_URL | backend.serviceUrls.WALLET_ADDRESS_URL | http://127.0.0.1:3001/.well-known/pay | Internal base wallet address URL used by the backend service. Each tenant’s wallet address base is configured via settings and cannot be updated once set; this variable does not override tenant settings. |
WALLET_ADDRESS_WORKER_IDLE | backend.workerIdle | 200 | The time, in milliseconds, that WALLET_ADDRESS_WORKERS wait until checking the empty wallet address request queue again. |
WALLET_ADDRESS_WORKERS | backend.workers.walletAddress | 1 | The number of workers processing wallet address requests. |
WEBHOOK_MAX_RETRY | backend.webhookMaxRetry | 10 | The maximum number of times your Rafiki instance’s backend retries sending a certain webhook event to your configured WEBHOOK_URL . |
WEBHOOK_TIMEOUT | backend.lifetime.webhook | 2000 (2 seconds) | The time, in milliseconds, that your Rafiki instance will wait for a 200 response from your webhook endpoint. If a 200 response is not received, Rafiki will time out and try to send the webhook event again. |
WEBHOOK_WORKER_IDLE | backend.workerIdle | 200 | The time, in milliseconds, that WEBHOOK_WORKERS will wait until they check the empty webhook event queue again. |
WEBHOOK_WORKERS | backend.workers.webhook | 1 | The number of workers processing webhook events. |
WITHDRAWAL_THROTTLE_DELAY | backend.withdrawalThrottleDelay | undefined | The delay in liquidity withdrawal processing. |