Download OpenAPI specification:
The Grey Finance Business API lets you programmatically move money, check balances, look up exchange rates, and manage integration settings for your Grey Finance business account.
| Environment | URL |
|---|---|
| Sandbox | https://businessapi-sandbox.grey.co |
| Production | https://businessapi.grey.co |
All API requests must be authenticated using an API key. The key
should be included in the Authorization header of every request.
To generate your API key, log in to the dashboard:
API keys consist of a Public Key and a Secret Key:
gbpk_ (e.g. gbpk_abc123def456ghi789).gbsk_ (e.g. gbsk_xyz789uvw456rst123).Secure your API key
- Copy the generated key immediately — it will not be shown again.
- Store it securely in your application's environment variables.
- Never commit API keys to version control.
Include your API key in the Authorization header of every request:
curl -X GET "https://${baseUrl}/v1/grey-tags/johndoe" \
-H "Authorization: Bearer gbsk_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json"
Money-moving requests can be made safe to retry in two ways:
X-Idempotency-Key header, orreference in the body of a payout (/v1/charge/payout).When a request is retried with the same idempotency key — or the same
reference for the same business — Grey returns the original
response instead of performing the payment again, and sets
X-Idempotent-Replayed: true on the replayed response. A duplicate that
arrives while the first is still processing returns 409 Conflict.
Only successful (2xx) responses are replayed, so a payout that failed
can be retried under the same reference. Reusing a reference with a
different request body is rejected with 409 Conflict, so a genuine
second payment is never silently swallowed. Replays are matched for 24
hours.
Currently we support three event types for webhooks:
| Event | Description |
|---|---|
transaction.created |
New transaction created |
transaction.success |
Transaction completed successfully |
transaction.failed |
Transaction failed |
Every webhook payload echoes your client_reference (when you supplied
a reference on the request) alongside Grey's own
transaction_reference, so you can match each event to your records.
You can also look a transaction up at any time with
GET /api/v1/transactions?client_reference=....
Every webhook payload includes a cryptographic signature in the
X-Webhook-Signature header, computed with your webhook secret
and the raw request body using HMAC-SHA256.
X-Webhook-Signature: sha256=abc123def456...
X-Webhook-Signature header.package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"io"
"net/http"
"strings"
)
const webhookSecret = "your-webhook-secret-here"
func validateSignature(payload []byte, signatureHeader, secret string) bool {
if !strings.HasPrefix(signatureHeader, "sha256=") {
return false
}
expectedSignature := strings.TrimPrefix(signatureHeader, "sha256=")
h := hmac.New(sha256.New, []byte(secret))
h.Write(payload)
computedSignature := hex.EncodeToString(h.Sum(nil))
return hmac.Equal([]byte(computedSignature), []byte(expectedSignature))
}
func webhookHandler(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body", http.StatusBadRequest)
return
}
defer r.Body.Close()
signatureHeader := r.Header.Get("X-Webhook-Signature")
if signatureHeader == "" {
http.Error(w, "Missing signature header", http.StatusUnauthorized)
return
}
if !validateSignature(body, signatureHeader, webhookSecret) {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("Webhook received and validated successfully"))
}
Headers:
Content-Type: application/json
X-Webhook-Event: transaction.success
X-Webhook-Delivery-ID: delivery-uuid-123
X-Webhook-Signature: sha256=abc123def456...
User-Agent: Grey-Webhook/1.0
Body:
{
"event_type": "transaction.success",
"transaction_id": "txn_abc123def456",
"transaction_reference": "GREY7F3K2MQ9",
"client_reference": "INV-2024-001",
"business_id": "business-uuid",
"amount": 1000.00,
"source_currency": "USD",
"destination_currency": "EUR",
"status": "completed",
"fees": 5.00,
"fee_currency": "USD",
"exchange_rate": 0.85,
"created_at": "2024-01-15T10:30:00Z",
"completed_at": "2024-01-15T11:30:00Z",
"transaction_type": "p2p"
}
Check if a Grey Tag (username) exists and retrieve basic user information. Use this before initiating a P2P transfer.
| tag required | string Example: johndoe The Grey Tag to validate. |
{- "status": "success",
- "message": "User fetched successfully",
- "data": {
- "is_valid": true,
- "first_name": "John",
- "last_name": "Doe",
- "user_name": "johndoe"
}
}Get the list of payout methods you can use with
/v1/charge/payout, including the supported currencies,
countries, and the required beneficiary fields for each.
{- "status": "success",
- "message": "Payout methods fetched successfully",
- "data": {
- "payout_methods": [
- {
- "name": "bank_account",
- "title": "Bank Transfer",
- "description": "Send money to a bank account",
- "currencies": [
- "EUR",
- "GBP",
- "NGN",
- "USD"
], - "countries": [
- "DE",
- "GB",
- "NG",
- "US"
], - "required_fields": [
- "account_number",
- "bank_code",
- "first_name",
- "last_name"
], - "average_processing_time": "1-3 business days"
}, - {
- "name": "mobile_money",
- "title": "Mobile Money",
- "description": "Send money to a mobile wallet",
- "currencies": [
- "GHS",
- "KES"
], - "countries": [
- "GH",
- "KE"
], - "required_fields": [
- "phone_number",
- "first_name",
- "last_name"
], - "average_processing_time": "1-30 minutes"
}
]
}
}Get the list of currency pairs you can swap with
/v1/charge/swap and quote with /v1/currency/rate.
{- "status": "success",
- "message": "Currency pairs fetched successfully",
- "data": {
- "currency_pairs": [
- {
- "source": "EUR",
- "destination": "NGN"
}, - {
- "source": "GBP",
- "destination": "USD"
}, - {
- "source": "USD",
- "destination": "EUR"
}, - {
- "source": "USD",
- "destination": "NGN"
}
]
}
}Get your Grey Finance business wallet balances across all currencies. Returns one entry per currency wallet your business has provisioned, sorted alphabetically by currency code.
Use this to reconcile balances on your end before initiating swaps, payouts, or P2P transfers.
{- "status": "success",
- "message": "Balances fetched successfully",
- "data": {
- "balances": [
- {
- "currency": "BTC",
- "currency_type": "crypto",
- "available_balance": 0.00123,
- "pending_balance": 0
}, - {
- "currency": "NGN",
- "currency_type": "fiat",
- "available_balance": 250000,
- "pending_balance": 0
}, - {
- "currency": "USD",
- "currency_type": "fiat",
- "available_balance": 12345.67,
- "pending_balance": 100.5
}
]
}
}Send money to someone using their Grey Tag (username).
| source_amount required | number Amount to send. |
| source_currency required | string ISO currency code of the source wallet. |
| destination_currency required | string ISO currency code for the recipient. |
| username required | string Recipient's Grey Tag. |
| description required | string A note or reference for this transfer. |
{- "source_amount": 50,
- "source_currency": "USD",
- "destination_currency": "USD",
- "username": "recipient_username",
- "description": "Payment for services"
}{- "status": "success",
- "message": "transaction is processing",
- "data": {
- "id": "550e8400-e29b-41d4-a716-446655440000",
- "reference": "txn_1234567890",
- "status": "processing",
- "source_amount": 50,
- "source_currency": "USD",
- "destination_amount": 50,
- "destination_currency": "USD"
}
}Convert one currency to another (e.g. USD to EUR).
| source_amount required | number Amount to convert. |
| source_currency required | string Currency to convert from. |
| destination_currency required | string Currency to convert to. |
{- "source_amount": 1000,
- "source_currency": "USD",
- "destination_currency": "EUR"
}{- "status": "success",
- "message": "Swap processing has been initiated",
- "data": {
- "id": "550e8400-e29b-41d4-a716-446655440000",
- "reference": "txn_1234567890",
- "status": "processing",
- "source_amount": 1000,
- "source_currency": "USD",
- "destination_amount": 850,
- "destination_currency": "EUR"
}
}Get current exchange rates and fees before making a transaction.
The transaction_type field must be one of withdraw, deposit,
or swap.
| source_amount required | number Amount to quote. |
| source_currency required | string |
| destination_currency required | string |
| transaction_type required | string Enum: "withdraw" "deposit" "swap" Type of transaction to quote fees for. |
{- "source_amount": 1000,
- "source_currency": "USD",
- "destination_currency": "EUR",
- "transaction_type": "swap"
}{- "status": "success",
- "message": "Currency rate created successfully",
- "data": {
- "source_amount": 1000,
- "source_currency": "USD",
- "destination_currency": "EUR",
- "destination_amount": 850,
- "withdrawal_fee": 0,
- "deposit_fee": 0,
- "swap_fee": 2.5,
- "source_destination_currency_rate": 0.85,
- "destination_source_currency_rate": 1.1765
}
}Send money from your Grey Finance business account to a bank
account. Use /v1/payout-methods to discover supported
rails and required beneficiary fields.
Pass your own reference to reconcile the payout against your
records — it is echoed back as client_reference on the response,
on GET /api/v1/transactions, and on webhooks. The same
reference also makes the request idempotent (see the
Idempotency section).
| source_amount required | number Amount to pay out. |
| source_currency required | string |
| destination_currency required | string |
| description | string A note or reference for this payout. |
| reference | string <= 128 characters Your own reference for this payout — for example an invoice,
order, or ledger id. It is stored and echoed back as
It also acts as an idempotency key: retrying a payout with the
same |
required | object (Beneficiary) Recipient details for a payout. The required fields depend on
the payout method and destination country — use
|
{- "source_amount": 500,
- "source_currency": "USD",
- "destination_currency": "USD",
- "description": "Business payout",
- "reference": "INV-1001",
- "beneficiary": {
- "first_name": "John",
- "last_name": "Doe",
- "account_number": "1234567890",
- "routing_number": "021000021",
- "bank_name": "Chase Bank",
- "account_type": "checking",
- "bank_country_code": "US",
- "scheme": "ACH",
- "payment_purpose": "Family Maintenance"
}
}{- "status": "success",
- "message": "Your withdrawal is processing",
- "data": {
- "id": "550e8400-e29b-41d4-a716-446655440000",
- "reference": "txn_1234567890",
- "client_reference": "INV-1001",
- "status": "processing",
- "source_amount": 500,
- "source_currency": "USD",
- "destination_amount": 500,
- "destination_currency": "USD"
}
}Retrieve your business's transactions, most recent first. Filter by
client_reference to look up the payment(s) you created with a
given reference, or by Grey reference for a specific transaction.
Every row includes client_reference for reconciliation.
| client_reference | string Example: client_reference=INV-1001 Return only transactions you created with this reference. |
| reference | string Return the transaction with this Grey reference. |
| page | integer >= 1 Page number for pagination. |
| limit | integer Number of results per page. |
{- "status": "success",
- "message": "Transactions retrieved",
- "data": [
- {
- "id": "550e8400-e29b-41d4-a716-446655440000",
- "reference": "txn_1234567890",
- "client_reference": "INV-1001",
- "status": "completed",
- "source_amount": 500,
- "source_currency": "USD",
- "destination_amount": 500,
- "destination_currency": "USD"
}
]
}Credit your business wallet with test funds so you can exercise payouts, swaps, and P2P transfers without making a real deposit.
This endpoint is only available in the sandbox environment —
calling it against production returns 404 Not Found.
The credit is applied immediately to the available_balance of the
wallet for the requested currency. If your business does not yet
have a wallet for that currency the request fails.
| currency required | string ISO currency code (fiat) or ticker (crypto) of the wallet to credit. |
| amount required | number Amount of test funds to credit. Must be greater than 0. |
{- "currency": "USD",
- "amount": 1000
}{- "status": "success",
- "message": "Wallet topped up successfully",
- "data": {
- "currency": "USD",
- "currency_type": "fiat",
- "available_balance": 13345.67,
- "pending_balance": 100.5
}
}Create a new API key for your business. The secret key is returned only once in the response — store it securely.
Note: This endpoint requires dashboard authentication (Bearer JWT), not an API key.
| name required | string Friendly name for the key. |
| description required | string |
| expires_at | string <date-time> Optional expiry timestamp. Omit for no expiry. |
| ip_whitelist | Array of strings IP addresses allowed to use this key. |
| ip_whitelist_enabled | boolean Whether to enforce IP whitelist. |
{- "name": "grey-api-key",
- "description": "This key is to process transactions",
- "expires_at": "2024-01-15T10:30:00Z",
- "ip_whitelist": [
- "127.0.0.1"
], - "ip_whitelist_enabled": true
}{- "id": "0b6ed51d-ccfb-4264-8d29-8f5753c67e92",
- "business_id": "0b6ed51d-ccfb-4264-8d29-8f5753c67e92",
- "name": "grey-api-key",
- "description": "This key is to process transactions",
- "active": true,
- "key": "gbpk_abc123def456ghi789",
- "secret_key": "gbsk_abc123def456ghi789",
- "ip_whitelist": [
- "127.0.0.1"
], - "ip_whitelist_enabled": true,
- "permissions": [
- "*"
], - "created_at": "2024-01-15T10:30:00Z",
- "updated_at": "2024-01-15T10:30:00Z",
- "last_used_at": "2024-01-15T10:30:00Z",
- "message": "Api key created successfully"
}Configure a webhook endpoint for your business to receive real-time notifications about transaction events.
Note: This endpoint requires dashboard authentication (Bearer JWT), not an API key.
| url required | string <uri> The HTTPS endpoint that will receive webhook events. |
| secret required | string >= 8 characters Secret used to compute HMAC-SHA256 signatures. |
| event_types required | Array of strings Items Enum: "transaction.created" "transaction.success" "transaction.failed" Events to subscribe to. |
| description | string |
{- "secret": "your-webhook-secret-key",
- "event_types": [
- "transaction.created",
- "transaction.success",
- "transaction.failed"
], - "description": "Production webhook"
}{- "id": "webhook-uuid-123",
- "event_types": [
- "transaction.created",
- "transaction.success",
- "transaction.failed"
], - "active": true,
- "created_at": "2024-01-15T10:30:00Z"
}