Influenzic’s gateway registry is fully extensible. Any developer can register a custom gateway by filtering inzc_payment_gateways and providing a descriptor array. No core files need to be edited, and webhook REST endpoints are auto-registered from the descriptor — you do not need to call register_rest_route() yourself.
The Registry Filter
The filter fires at plugins_loaded priority 20. Addon plugins that hook at the default priority (10) are always registered in time.
add_filter( 'inzc_payment_gateways', function( array $gateways ): array {
$gateways['my_gateway'] = [
'id' => 'my_gateway',
'label' => __( 'My Gateway', 'my-addon' ),
'class' => My_AddonMy_Gateway::class,
'webhook_slug' => 'my-gateway', // URL-safe [a-z0-9_-]
'redux_fields' => [
[
'id' => 'inzc_my_gateway_api_key',
'type' => 'password',
'title' => 'API Key',
'default' => '',
],
[
'id' => 'inzc_my_gateway_webhook_secret',
'type' => 'password',
'title' => 'Webhook Secret',
'default' => '',
],
],
];
return $gateways;
} );
Descriptor Keys
| Key | Required | Description |
|---|---|---|
id |
Yes | Unique gateway slug. Used as the array key, in database references, and as the gateway parameter in REST/AJAX calls. |
label |
Yes | Human-readable name shown in the settings panel and on the checkout page. |
class |
Yes | Fully-qualified class name implementing InfluenzicApiGatewaysGateway_Interface. |
webhook_slug |
Yes | Appended to /influenzic/v1/webhook/{slug} for the auto-registered webhook endpoint. Must be URL-safe. |
redux_fields |
Yes | Array of Redux Framework field arrays. These are rendered automatically in Influenzic → Settings under a tab named after your gateway label. Pass an empty array if no settings are needed. |
The Gateway Interface
Your class must implement InfluenzicApiGatewaysGateway_Interface. Below is a complete, fully implemented example showing how to retrieve settings, perform an API request to a gateway, handle webhook validations, verify HMAC signatures, and dispatch payment triggers.
namespace My_Addon;
use InfluenzicApiGatewaysGateway_Interface;
class My_Gateway implements Gateway_Interface {
/**
* Retrieve gateway options from the Redux framework settings.
*/
private function get_api_key(): string {
// Use the inzc_get_option helper function to retrieve options configured via redux_fields
return (string) inzc_get_option( 'inzc_my_gateway_api_key', '' );
}
private function get_webhook_secret(): string {
return (string) inzc_get_option( 'inzc_my_gateway_webhook_secret', '' );
}
/**
* Initiate a payment. Called at checkout time.
* $order_data contains: brand_id, campaign_id, campaign_title, batch_id,
* offers, totals (subtotal/fee/total), payment_type (e.g. checkout, topup),
* cancel_url, return_url.
* Return an array or WP_Error.
*/
public function initiate( array $order_data ) {
$total = $order_data['totals']['total'];
$batch_id = $order_data['batch_id'];
$payment_type = $order_data['payment_type'];
// Build request payload for the external gateway API
$payload = [
'amount' => $total, // amount in minor units
'currency' => get_option( 'inzc_currency', 'USD' ),
'reference' => $batch_id,
'callback' => $order_data['return_url'],
'metadata' => [
'inzc_payment_type' => $payment_type, // IMPORTANT: required for dispatcher
'inzc_batch_id' => $batch_id,
'brand_id' => $order_data['brand_id'],
]
];
// Perform the API post request
$response = wp_remote_post( 'https://api.mygateway.example/v1/charges', [
'body' => wp_json_encode( $payload ),
'headers' => [
'Authorization' => 'Bearer ' . $this->get_api_key(),
'Content-Type' => 'application/json'
]
] );
if ( is_wp_error( $response ) ) {
return $response; // Return WP_Error to show standard checkout error notice
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $body['status'] ) || 'success' !== $body['status'] ) {
return new WP_Error( 'gateway_initiate_failed', $body['message'] ?? 'Failed to connect to provider.' );
}
return [
'success' => true,
'gateway' => 'my_gateway',
'redirect_url' => $body['checkout_url'],
'order_ref' => $batch_id,
];
}
/**
* Verify a payment reference after redirect or in a webhook.
* Return true only when the gateway confirms the charge succeeded.
*/
public function verify( string $reference ): bool {
$response = wp_remote_get( "https://api.mygateway.example/v1/charges/{$reference}", [
'headers' => [
'Authorization' => 'Bearer ' . $this->get_api_key()
]
] );
if ( is_wp_error( $response ) ) {
return false;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
return ! empty( $body['paid'] ) && true === $body['paid'];
}
/**
* Handle an inbound webhook from the gateway.
* 1. Verify the payload signature using the webhook secret.
* 2. Extract 'inzc_payment_type' from the metadata stored at initiate() time.
* 3. Call inzc_dispatch_payment_complete( $payment_type, $metadata, $totals ).
*/
public function handle_webhook( WP_REST_Request $request ): WP_REST_Response {
$signature = $request->get_header( 'X-MyGateway-Signature' );
$payload = $request->get_body();
// 1. Verify webhook signature (HMAC SHA256)
$expected = hash_hmac( 'sha256', $payload, $this->get_webhook_secret() );
if ( ! hash_equals( $expected, (string) $signature ) ) {
return new WP_REST_Response( ['error' => 'Invalid signature'], 400 );
}
$data = json_decode( $payload, true );
if ( empty( $data['metadata']['inzc_payment_type'] ) ) {
return new WP_REST_Response( ['error' => 'Missing payment type metadata'], 400 );
}
// 2. Extracted values
$payment_type = $data['metadata']['inzc_payment_type']; // "checkout" or "topup"
$metadata = $data['metadata'];
$totals = [
'total' => $data['amount'] // amount received in minor units
];
// 3. Dispatch the complete operation
// The dispatcher handles invoice/escrow routing automatically based on payment_type
inzc_dispatch_payment_complete( $payment_type, $metadata, $totals );
return new WP_REST_Response( ['received' => true], 200 );
}
/**
* Return the ISO 4217 currency codes this gateway can process.
* Return an empty array to indicate no restriction (accepts all currencies).
*/
public function supported_currencies(): array {
return ['NGN', 'GHS', 'ZAR', 'USD'];
}
}
/wp-json/influenzic/v1/webhook/my-gateway automatically using the webhook_slug from your descriptor. Do not call register_rest_route() yourself — the Webhook_Controller handles all gateway routing.
Currency Filtering
The registry uses supported_currencies() to automatically exclude gateways that cannot process the operator’s configured platform currency. An operator running NGN will not see Stripe-only gateways if you restrict yours to NGN. Return an empty array ([]) if your gateway accepts all currencies (as Stripe does).
Subscription Support (Optional)
If your gateway supports recurring billing, also implement:
charge_renewal( string $gateway_subscription_id, float $amount, array $context )— called by the subscription cron on renewal datescancel_subscription( string $gateway_subscription_id )— called when a brand cancels their plan
Gateways that do not support subscriptions may return a WP_Error with code gateway_manual_renewal from charge_renewal() to trigger the manual-renewal fallback flow.