Skip to main content

GraphQL API Reference

The iNPAY GraphQL API provides a flexible and efficient way to interact with our payment services. GraphQL allows you to request exactly the data you need in a single request.

🔗 Endpoint

  • Production: https://api.inpaycheckout.com/graphql
  • Development: https://sandbox-api.inpaycheckout.com/graphql

🔑 Authentication

Include your secret key in the Authorization header:

Authorization: Bearer sk_live_your_secret_key_here
Content-Type: application/json

🚀 Basic Usage

Making Requests

curl -X POST https://api.inpaycheckout.com/graphql \
-H "Authorization: Bearer sk_live_your_secret_key" \
-H "Content-Type: application/json" \
-d '{
"query": "query { healthCheck { success message timestamp version } }"
}'

📋 Mutations

Create Dynamic PayID

mutation CreateDynamicPayId($input: CreateDynamicPayIdInput!) {
createDynamicPayId(input: $input) {
success
message
data {
payId
name
reference
expiresAt
status
type
}
}
}

Variables:

{
"input": {
"reference": "unique-ref-123",
"metadata": {
"orderId": "ORDER-456",
"customerEmail": "customer@example.com"
}
}
}

Create Static PayID

mutation CreateStaticPayId($input: CreateStaticPayIdInput!) {
createStaticPayId(input: $input) {
success
message
data {
payId
name
reference
status
type
}
}
}

Variables:

{
"input": {
"name": "My Custom PayID",
"reference": "unique-ref-456",
"metadata": {
"businessUnit": "sales",
"region": "lagos"
}
}
}

Create Virtual Account

mutation CreateVirtualAccount($input: CreateVirtualAccountInput!) {
createVirtualAccount(input: $input) {
success
message
data {
accountNumber
accountName
bankName
reference
amount
currency
expiresAt
validityTime
amountValidation
}
}
}

Variables:

{
"input": {
"amount": 50000,
"name": "Custom Account Name",
"reference": "unique-ref-789",
"validityTime": 1440,
"amountValidation": "A0",
"metadata": {
"productId": "PROD-123",
"campaignId": "CAMP-456"
}
}
}

Verify Transaction

mutation VerifyTransaction($input: VerifyTransactionInput!) {
verifyTransaction(input: $input) {
success
message
data {
reference
type
payId
accountNumber
status
verified
customerEmail
customerName
amount
createdAt
updatedAt
}
}
}

Variables:

{
"input": {
"reference": "unique-ref-123"
}
}

Response (Verified - Completed):

{
"success": true,
"message": "Transaction verified successfully",
"data": {
"reference": "unique-ref-123",
"type": "virtual_account",
"accountNumber": "1036262911",
"status": "completed",
"verified": true,
"customerEmail": "customer@example.com",
"customerName": "John Doe",
"amount": 100000,
"createdAt": "2025-09-14T10:00:00.000Z",
"updatedAt": "2025-09-14T10:15:00.000Z"
}
}

Response (Not Verified - Pending):

{
"success": true,
"message": "Payment verification completed",
"data": {
"reference": "unique-ref-123",
"type": "virtual_account",
"accountNumber": "1036262911",
"status": "pending",
"verified": false,
"customerEmail": "customer@example.com",
"customerName": "John Doe",
"amount": 100000,
"createdAt": "2025-09-14T10:00:00.000Z",
"updatedAt": "2025-09-14T10:00:00.000Z"
}
}

Note: The amount field behavior:

  • When status is pending: Returns the expected amount (in kobo) that was specified when creating the virtual account/PayID
  • When status is completed: Returns the actual amount received (in kobo) from the transaction record

This ensures:

  • Backward compatibility: amount is always a number, never null
  • Merchants see the expected amount while waiting for payment
  • Once payment is received, merchants see the actual amount (which may differ if user sent less than expected)
  • The status field clearly indicates whether payment is pending or completed

Verify PayID

mutation VerifyPayId($input: VerifyPayIdInput!) {
verifyPayId(input: $input) {
success
message
data {
payId
accountName
isVirtualPayId
isActive
expiresAt
type
}
}
}

Variables:

{
"input": {
"payId": "merchant123.dpid"
}
}

PayID-to-PayID Transfer

mutation TransferPayId($input: PayIdTransferInput!) {
transferPayId(input: $input) {
success
message
data {
transactionId
reference
fromPayId
toPayId
amount
narration
status
completedAt
destinationAccountName
}
}
}

Variables:

{
"input": {
"fromPayId": "mywallet123.wallet",
"toPayId": "customer456.dpid",
"amount": 5000,
"narration": "Payment for order #12345",
"reference": "TXN-789"
}
}

Verify External Account

mutation VerifyExternalAccount($input: VerifyExternalAccountInput!) {
verifyExternalAccount(input: $input) {
success
message
data {
accountNumber
accountName
bankCode
bankName
bankLogo
verified
}
}
}

Variables:

{
"input": {
"accountNumber": "1234567890",
"bankCode": "058"
}
}

External Bank Transfer

mutation TransferExternal($input: ExternalTransferInput!) {
transferExternal(input: $input) {
success
message
data {
transactionId
reference
fromPayId
toAccountNumber
toAccountName
bankCode
bankName
amount
narration
status
completedAt
}
}
}

Variables:

{
"input": {
"fromPayId": "mywallet123.wallet",
"accountNumber": "1234567890",
"bankCode": "058",
"amount": 10000,
"narration": "Payment to supplier",
"reference": "PAY-456",
"accountName": "John Doe"
}
}

🔍 Queries

Get Transaction Status

query GetTransactionStatus($input: GetTransactionStatusInput!) {
getTransactionStatus(input: $input) {
success
message
data {
reference
type
payId
accountNumber
status
verified
customerEmail
customerName
amount
createdAt
updatedAt
}
}
}

Variables:

{
"input": {
"reference": "unique-ref-123"
}
}

Response (Completed Payment):

{
"success": true,
"message": "Transaction status retrieved successfully",
"data": {
"reference": "unique-ref-123",
"type": "virtual_payid",
"payId": "mydyn456.dpid",
"status": "completed",
"verified": true,
"customerEmail": "customer@example.com",
"customerName": "Customer",
"amount": 100000,
"createdAt": "2025-09-14T10:00:00.000Z",
"updatedAt": "2025-09-14T10:15:00.000Z"
}
}

Response (Pending Payment):

{
"success": true,
"message": "Transaction status retrieved successfully",
"data": {
"reference": "unique-ref-123",
"type": "virtual_account",
"accountNumber": "1036262911",
"status": "pending",
"verified": false,
"customerEmail": "customer@example.com",
"customerName": "Customer",
"amount": 100000,
"createdAt": "2025-09-14T10:00:00.000Z",
"updatedAt": "2025-09-14T10:00:00.000Z"
}
}

Note: The amount field behavior:

  • When status is pending: Returns the expected amount (in kobo) that was specified when creating the virtual account/PayID
  • When status is completed: Returns the actual amount received (in kobo) from the transaction record

This ensures:

  • Backward compatibility: amount is always a number, never null
  • Merchants see the expected amount while waiting for payment
  • Once payment is received, merchants see the actual amount (which may differ if user sent less than expected)
  • The status field clearly indicates whether payment is pending or completed

Health Check

query HealthCheck {
healthCheck {
success
message
timestamp
version
}
}

Get Bank List

query GetBankList {
getBankList {
success
message
data {
banks {
bankCode
bankName
logoUrl
}
total
}
}
}

💻 Code Examples

JavaScript/Node.js

const axios = require('axios');

class InpayGraphQLClient {
constructor(secretKey, endpoint = 'https://api.inpaycheckout.com/graphql') {
this.secretKey = secretKey;
this.endpoint = endpoint;
this.headers = {
'Authorization': `Bearer ${secretKey}`,
'Content-Type': 'application/json'
};
}

async execute(query, variables = {}) {
try {
const response = await axios.post(this.endpoint, {
query,
variables
}, {
headers: this.headers
});

if (response.data.errors) {
throw new Error(`GraphQL Error: ${response.data.errors[0].message}`);
}

return response.data.data;
} catch (error) {
console.error('GraphQL execution error:', error.message);
throw error;
}
}

// Create Dynamic PayID
async createDynamicPayID(reference, metadata = {}) {
const query = `
mutation CreateDynamicPayId($input: CreateDynamicPayIdInput!) {
createDynamicPayId(input: $input) {
success
message
data {
payId
name
reference
expiresAt
status
type
}
}
}
`;

const variables = {
input: {
reference,
metadata
}
};

return await this.execute(query, variables);
}

// Create Virtual Account
async createVirtualAccount(amount, reference, options = {}) {
const query = `
mutation CreateVirtualAccount($input: CreateVirtualAccountInput!) {
createVirtualAccount(input: $input) {
success
message
data {
accountNumber
accountName
bankName
reference
amount
currency
expiresAt
validityTime
amountValidation
}
}
}
`;

const variables = {
input: {
amount,
reference,
name: options.name,
validityTime: options.validityTime || 1440,
amountValidation: options.amountValidation || 'A1',
metadata: options.metadata || {}
}
};

return await this.execute(query, variables);
}

// Transfer PayID
async transferPayID(fromPayID, toPayID, amount, narration, reference) {
const query = `
mutation TransferPayId($input: PayIdTransferInput!) {
transferPayId(input: $input) {
success
message
data {
transactionId
reference
fromPayId
toPayId
amount
narration
status
completedAt
destinationAccountName
}
}
}
`;

const variables = {
input: {
fromPayId: fromPayID,
toPayId: toPayID,
amount,
narration,
reference
}
};

return await this.execute(query, variables);
}

// Get Bank List
async getBankList() {
const query = `
query GetBankList {
getBankList {
success
message
data {
banks {
bankCode
bankName
logoUrl
}
total
}
}
}
`;

return await this.execute(query);
}

// Health Check
async healthCheck() {
const query = `
query HealthCheck {
healthCheck {
success
message
timestamp
version
}
}
`;

return await this.execute(query);
}
}

// Usage
const client = new InpayGraphQLClient(process.env.INPAY_SECRET_KEY);

// Create Dynamic PayID
const payID = await client.createDynamicPayID('order-123', {
orderId: 'ORDER-456',
customerEmail: 'customer@example.com'
});

console.log('PayID created:', payID.createDynamicPayId.data.payId);

// Create Virtual Account
const virtualAccount = await client.createVirtualAccount(50000, 'order-456', {
name: 'Order Payment',
validityTime: 1440,
metadata: {
productId: 'PROD-123'
}
});

console.log('Virtual Account created:', virtualAccount.createVirtualAccount.data.accountNumber);

// Transfer PayID
const transfer = await client.transferPayID(
'mywallet123.wallet',
'customer456.dpid',
5000,
'Payment for order #12345',
'TXN-789'
);

console.log('Transfer completed:', transfer.transferPayId.data.transactionId);

// Get Bank List
const bankList = await client.getBankList();
console.log('Supported banks:', bankList.getBankList.data.banks.length);

Python

import requests
import json

class InpayGraphQLClient:
def __init__(self, secret_key, endpoint='https://api.inpaycheckout.com/graphql'):
self.secret_key = secret_key
self.endpoint = endpoint
self.headers = {
'Authorization': f'Bearer {secret_key}',
'Content-Type': 'application/json'
}

def execute(self, query, variables=None):
"""Execute GraphQL query"""
try:
response = requests.post(
self.endpoint,
json={
'query': query,
'variables': variables or {}
},
headers=self.headers
)

data = response.json()

if 'errors' in data:
raise Exception(f"GraphQL Error: {data['errors'][0]['message']}")

return data['data']
except Exception as e:
print(f'GraphQL execution error: {e}')
raise

def create_dynamic_payid(self, reference, metadata=None):
"""Create Dynamic PayID"""
query = """
mutation CreateDynamicPayId($input: CreateDynamicPayIdInput!) {
createDynamicPayId(input: $input) {
success
message
data {
payId
name
reference
expiresAt
status
type
}
}
}
"""

variables = {
'input': {
'reference': reference,
'metadata': metadata or {}
}
}

return self.execute(query, variables)

def create_virtual_account(self, amount, reference, **options):
"""Create Virtual Account"""
query = """
mutation CreateVirtualAccount($input: CreateVirtualAccountInput!) {
createVirtualAccount(input: $input) {
success
message
data {
accountNumber
accountName
bankName
reference
amount
currency
expiresAt
validityTime
amountValidation
}
}
}
"""

variables = {
'input': {
'amount': amount,
'reference': reference,
'name': options.get('name'),
'validityTime': options.get('validityTime', 1440),
'amountValidation': options.get('amountValidation', 'A1'),
'metadata': options.get('metadata', {})
}
}

return self.execute(query, variables)

def transfer_payid(self, from_payid, to_payid, amount, narration, reference):
"""Transfer PayID"""
query = """
mutation TransferPayId($input: PayIdTransferInput!) {
transferPayId(input: $input) {
success
message
data {
transactionId
reference
fromPayId
toPayId
amount
narration
status
completedAt
destinationAccountName
}
}
}
"""

variables = {
'input': {
'fromPayId': from_payid,
'toPayId': to_payid,
'amount': amount,
'narration': narration,
'reference': reference
}
}

return self.execute(query, variables)

def get_bank_list(self):
"""Get Bank List"""
query = """
query GetBankList {
getBankList {
success
message
data {
banks {
bankCode
bankName
logoUrl
}
total
}
}
}
"""

return self.execute(query)

def health_check(self):
"""Health Check"""
query = """
query HealthCheck {
healthCheck {
success
message
timestamp
version
}
}
"""

return self.execute(query)

# Usage
client = InpayGraphQLClient(os.getenv('INPAY_SECRET_KEY'))

# Create Dynamic PayID
payid = client.create_dynamic_payid('order-123', {
'orderId': 'ORDER-456',
'customerEmail': 'customer@example.com'
})

print(f"PayID created: {payid['createDynamicPayId']['data']['payId']}")

# Create Virtual Account
virtual_account = client.create_virtual_account(
50000,
'order-456',
name='Order Payment',
validityTime=1440,
metadata={'productId': 'PROD-123'}
)

print(f"Virtual Account created: {virtual_account['createVirtualAccount']['data']['accountNumber']}")

# Transfer PayID
transfer = client.transfer_payid(
'mywallet123.wallet',
'customer456.dpid',
5000,
'Payment for order #12345',
'TXN-789'
)

print(f"Transfer completed: {transfer['transferPayId']['data']['transactionId']}")

# Get Bank List
bank_list = client.get_bank_list()
print(f"Supported banks: {len(bank_list['getBankList']['data']['banks'])}")

🔍 GraphQL vs REST

FeatureGraphQLREST
Data FetchingRequest only needed fieldsGet complete resources
Multiple OperationsSingle request for multiple operationsMultiple requests required
Type SafetyStrong typing with schemaNo built-in typing
CachingMore complex cachingStandard HTTP caching
Learning CurveSteeper learning curveFamiliar HTTP concepts

🚨 Error Handling

GraphQL errors are returned in the errors field:

{
"data": null,
"errors": [
{
"message": "Invalid secret key",
"locations": [{"line": 2, "column": 3}],
"path": ["createDynamicPayId"]
}
]
}

💡 Best Practices

✅ Do's

  • Use specific field selection - Request only the fields you need
  • Handle errors gracefully - Check for errors in the response
  • Use variables - Pass data through variables, not string interpolation
  • Implement retry logic - Handle network failures and retries
  • Cache responses - Implement appropriate caching strategies

❌ Don'ts

  • Don't request all fields - Be specific about what data you need
  • Don't ignore errors - Always check and handle GraphQL errors
  • Don't use string interpolation - Use variables for dynamic data
  • Don't make unnecessary requests - Batch operations when possible

Next Steps: