ForhoppPay Connect - Complete API Documentation
Overview
ForhoppPay Connect is an enterprise-grade merchant payment integration platform that enables external businesses to accept payments through ForhoppPay. Similar to Stripe Connect or PayPal Commerce Platform, it provides:
- API Keys - Publishable and secret key pairs for authentication
- Charge API - Create, capture, and refund payments
- Hosted Checkout - Secure payment pages at pay.forhopp.com
- Webhooks - Real-time event notifications with signature verification
- Sandbox Environment - Test integration without real payments
- Multi-Currency Support - USD, EUR, GBP, CAD, AUD, JPY, CHF
Quick Start
1. Get Your API Keys
After enabling Connect on your ForhoppPay account, generate API keys from your dashboard:
Publishable Key: pk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
Secret Key: sk_live_q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2
- Publishable keys (
pk_*) are safe for client-side code - Secret keys (
sk_*) must be kept confidential on your server
2. Create a Charge
curl -X POST https://api.pay.forhopp.com/connect/v1/charges \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id" \
-d '{
"amount": 5000,
"currency": "usd",
"description": "Order #12345",
"return_url": "https://yoursite.com/success",
"cancel_url": "https://yoursite.com/cancel"
}'
3. Redirect to Checkout
Use the checkout_url from the response to redirect your customer:
window.location.href = response.checkout_url;
// https://pay.forhopp.com/checkout/ch_1234567890abcdef
4. Handle Webhooks
Configure a webhook endpoint to receive payment notifications:
app.post('/webhooks/forhopppay', (req, res) => {
const signature = req.headers['forhopppay-signature'];
const payload = req.body;
if (verifySignature(payload, signature, webhookSecret)) {
switch (payload.type) {
case 'charge.completed':
// Payment successful - fulfill order
break;
case 'charge.failed':
// Payment failed - notify customer
break;
}
}
res.status(200).send('OK');
});
Authentication
API Key Types
| Key Type | Format | Usage |
|---|---|---|
| Live Publishable | pk_live_[32 chars] |
Client-side, production |
| Live Secret | sk_live_[32 chars] |
Server-side, production |
| Test Publishable | pk_test_[32 chars] |
Client-side, sandbox |
| Test Secret | sk_test_[32 chars] |
Server-side, sandbox |
Making Authenticated Requests
Include your secret key in the Authorization header:
Authorization: Bearer sk_live_your_secret_key
Rate Limits
| Environment | Limit |
|---|---|
| Live (sk_live_*) | 100 requests/second |
| Test (sk_test_*) | 25 requests/second |
Rate limit headers are included in every response:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1234567890
When exceeded, you'll receive HTTP 429 with a Retry-After header.
API Reference
Base URL
https://api.pay.forhopp.com/connect/v1
API Versioning
Specify version via header (optional):
ForhoppPay-Version: 2024-01-01
If not specified, the latest stable version is used.
Charges API
Create a Charge
Creates a new charge and returns a checkout URL.
POST /charges
Headers:
Authorization: Bearer sk_*(required)Idempotency-Key: string(recommended)Content-Type: application/json
Request Body:
| Parameter | Type | Required | Description |
|---|---|---|---|
amount |
integer | Yes | Amount in cents (min: 50, max: 99999999) |
currency |
string | Yes | ISO currency code: usd, eur, gbp, cad, aud, jpy, chf |
description |
string | No | Description shown to customer (max 500 chars) |
metadata |
object | No | Key-value pairs for your use |
return_url |
string | Yes | Redirect URL after successful payment |
cancel_url |
string | No | Redirect URL if customer cancels |
Example Request:
{
"amount": 5000,
"currency": "usd",
"description": "Order #12345",
"metadata": {
"order_id": "12345",
"customer_email": "customer@example.com"
},
"return_url": "https://merchant.com/success",
"cancel_url": "https://merchant.com/cancel"
}
Response (201 Created):
{
"id": "ch_1234567890abcdef1234567890abcdef",
"object": "charge",
"amount": 5000,
"currency": "usd",
"status": "pending",
"description": "Order #12345",
"metadata": {
"order_id": "12345",
"customer_email": "customer@example.com"
},
"checkout_url": "https://pay.forhopp.com/checkout/ch_1234567890abcdef1234567890abcdef",
"return_url": "https://merchant.com/success",
"cancel_url": "https://merchant.com/cancel",
"expires_at": 1234654290,
"created": 1234567890,
"livemode": true
}
Retrieve a Charge
GET /charges/{charge_id}
Response (200 OK):
{
"id": "ch_1234567890abcdef1234567890abcdef",
"object": "charge",
"amount": 5000,
"currency": "usd",
"status": "captured",
"description": "Order #12345",
"payment_method": "card",
"payment_method_details": {
"card": {
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2025
}
},
"fee": 175,
"net": 4825,
"refunds": [],
"created": 1234567890,
"captured_at": 1234567900,
"livemode": true
}
List Charges
GET /charges?limit=10&status=captured
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
limit |
integer | Max results (1-100, default: 10) |
status |
string | Filter by status |
created_after |
integer | Unix timestamp filter |
created_before |
integer | Unix timestamp filter |
starting_after |
string | Cursor for pagination |
Response:
{
"object": "list",
"data": [...],
"has_more": true,
"url": "/api/v1/connect/charges",
"total_count": 150
}
Capture a Charge
Captures an authorized charge. Only charges with authorized status can be captured.
POST /charges/{charge_id}/capture
Request Body (optional for partial capture):
{
"amount": 3000
}
Response (200 OK):
{
"id": "ch_1234567890abcdef1234567890abcdef",
"status": "captured",
"amount": 5000,
"fee": 175,
"net": 4825,
"captured_at": 1234567900
}
Refund a Charge
Creates a refund for a captured charge. Supports partial refunds.
POST /charges/{charge_id}/refunds
Request Body:
{
"amount": 2500,
"reason": "customer_request"
}
Response (201 Created):
{
"id": "re_1234567890abcdef1234567890abcdef",
"object": "refund",
"charge": "ch_1234567890abcdef1234567890abcdef",
"amount": 2500,
"currency": "usd",
"status": "succeeded",
"reason": "customer_request",
"created": 1234567950
}
Charge Lifecycle
┌─────────┐
│ PENDING │ ──────────────────────────────────────┐
└────┬────┘ │
│ Customer completes payment │ 24h timeout
▼ ▼
┌────────────┐ ┌─────────┐
│ AUTHORIZED │ │ EXPIRED │
└─────┬──────┘ └─────────┘
│
├── Capture ──────────────────┐
│ ▼
│ ┌──────────┐
│ │ CAPTURED │
│ └────┬─────┘
│ │
│ ├── Partial Refund ──► PARTIALLY_REFUNDED
│ │
│ └── Full Refund ────► REFUNDED
│
├── Void ─────────────────────────────────► VOIDED
│
└── 7 days without capture ───────────────► VOIDED
Status Definitions
| Status | Description |
|---|---|
pending |
Charge created, awaiting customer payment |
authorized |
Payment authorized, ready for capture |
captured |
Payment captured, funds transferred |
failed |
Payment failed |
voided |
Charge cancelled before capture |
refunded |
Fully refunded |
partially_refunded |
Partially refunded |
expired |
Checkout session expired (24h) |
disputed |
Customer disputed the charge |
Webhooks
Webhook Events
| Event | Description |
|---|---|
charge.created |
Charge was created |
charge.completed |
Payment was successful |
charge.failed |
Payment failed |
charge.refunded |
Charge was refunded (full or partial) |
charge.disputed |
Customer disputed the charge |
payout.created |
Payout was initiated |
payout.completed |
Payout was successful |
payout.failed |
Payout failed |
Create Webhook Endpoint
POST /webhooks
Request:
{
"url": "https://merchant.com/webhooks/forhopppay",
"events": ["charge.completed", "charge.refunded", "charge.disputed"],
"description": "Production webhook"
}
Response:
{
"id": "we_1234567890abcdef",
"object": "webhook_endpoint",
"url": "https://merchant.com/webhooks/forhopppay",
"secret": "whsec_1234567890abcdef1234567890abcdef",
"events": ["charge.completed", "charge.refunded", "charge.disputed"],
"status": "enabled",
"created": 1234567890
}
Important: The
secretis only shown once at creation. Store it securely.
Webhook Payload Format
{
"id": "evt_1234567890abcdef12345678",
"object": "event",
"type": "charge.completed",
"created": 1234567890,
"livemode": true,
"data": {
"object": {
"id": "ch_1234567890abcdef1234567890abcdef",
"object": "charge",
"amount": 5000,
"currency": "usd",
"status": "captured",
"payment_method": "card",
"metadata": {
"order_id": "12345"
}
}
}
}
Signature Verification
Every webhook includes a ForhoppPay-Signature header:
ForhoppPay-Signature: t=1234567890,v1=abc123def456...
Verification Steps:
- Extract timestamp (
t) and signature (v1) from header - Check timestamp is within 5 minutes of current time
- Compute expected signature:
HMAC-SHA256(timestamp + "." + payload, webhook_secret) - Compare signatures using constant-time comparison
Java Example:
public boolean verifyWebhookSignature(String payload, String signature, String secret) {
String[] parts = signature.split(",");
String timestamp = null;
String v1Signature = null;
for (String part : parts) {
if (part.startsWith("t=")) {
timestamp = part.substring(2);
} else if (part.startsWith("v1=")) {
v1Signature = part.substring(3);
}
}
// Check timestamp is within 5 minutes
long timestampLong = Long.parseLong(timestamp);
if (System.currentTimeMillis() / 1000 - timestampLong > 300) {
return false;
}
// Compute expected signature
String signedPayload = timestamp + "." + payload;
String expectedSignature = HmacUtils.hmacSha256Hex(secret, signedPayload);
return MessageDigest.isEqual(
expectedSignature.getBytes(StandardCharsets.UTF_8),
v1Signature.getBytes(StandardCharsets.UTF_8)
);
}
Retry Schedule
Failed webhook deliveries are retried automatically:
| Attempt | Delay |
|---|---|
| 1 | 1 minute |
| 2 | 5 minutes |
| 3 | 30 minutes |
| 4 | 2 hours |
| 5 | 24 hours |
After 5 consecutive failures, the endpoint is marked as failing.
API Key Management
Create API Key
POST /keys
Authorization: Bearer {jwt_token}
Request:
{
"name": "Production Key",
"environment": "live"
}
Response:
{
"id": "key_1234567890abcdef",
"object": "api_key",
"name": "Production Key",
"publishable_key": "pk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"secret_key": "sk_live_q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2",
"environment": "live",
"created": 1234567890
}
Important: The
secret_keyis only shown once. Store it securely.
List API Keys
GET /keys
Authorization: Bearer {jwt_token}
Revoke API Key
DELETE /keys/{key_id}
Authorization: Bearer {jwt_token}
Sandbox Environment
Test API Keys
Use test keys (sk_test_*, pk_test_*) to test your integration without processing real payments.
Test Card Numbers
| Card Number | Behavior |
|---|---|
4242424242424242 |
Successful payment |
4000000000000002 |
Card declined |
4000000000009995 |
Insufficient funds |
4000000000000069 |
Expired card |
4000000000000127 |
Incorrect CVC |
4000000000000119 |
Processing error |
Test PayPal Accounts
| Behavior | |
|---|---|
test-buyer@forhopppay.com |
Successful payment |
test-declined@forhopppay.com |
Payment declined |
Sandbox Behavior
- No real payments are processed
- Webhooks are delivered to test endpoints
- Data is isolated from production
- Lower rate limits (25 req/sec)
Fee Structure
Platform Fees
| Fee Type | Amount |
|---|---|
| Transaction Fee | 2.9% + $0.30 |
| Currency Conversion | 1% above mid-market rate |
| Dispute Fee | $15 (refunded if won) |
Fee Calculation Example:
Charge Amount: $50.00 (5000 cents)
Percentage Fee: 5000 × 0.029 = 145 cents
Fixed Fee: 30 cents
Total Fee: 175 cents ($1.75)
Net Amount: 4825 cents ($48.25)
Payouts
| Schedule | Timing |
|---|---|
| Daily | 00:00 UTC |
| Weekly | Monday 00:00 UTC |
| Monthly | 1st of month 00:00 UTC |
Minimum payout threshold: $25
Supported Currencies
| Currency | Code | Minimum Charge |
|---|---|---|
| US Dollar | USD | $0.50 |
| Euro | EUR | €0.50 |
| British Pound | GBP | £0.50 |
| Canadian Dollar | CAD | CA$0.50 |
| Australian Dollar | AUD | A$0.50 |
| Japanese Yen | JPY | ¥50 |
| Swiss Franc | CHF | CHF 0.50 |
Error Handling
Error Response Format
{
"error": {
"type": "invalid_request_error",
"code": "parameter_invalid",
"message": "The amount must be a positive integer in cents.",
"param": "amount",
"doc_url": "https://docs.forhopppay.com/errors/parameter_invalid"
}
}
Error Types
| Type | HTTP Status | Description |
|---|---|---|
invalid_request_error |
400 | Invalid parameters |
authentication_error |
401 | Invalid API key |
authorization_error |
403 | Insufficient permissions |
resource_not_found |
404 | Resource doesn't exist |
idempotency_error |
409 | Idempotency key conflict |
rate_limit_error |
429 | Too many requests |
api_error |
500 | Internal error |
gateway_error |
502 | Payment gateway error |
Common Error Codes
| Code | Description |
|---|---|
parameter_missing |
Required parameter not provided |
parameter_invalid |
Parameter value is invalid |
amount_too_small |
Amount below minimum (50 cents) |
amount_too_large |
Amount exceeds maximum |
currency_unsupported |
Currency not supported |
charge_already_captured |
Charge already captured |
charge_already_refunded |
Charge fully refunded |
charge_expired |
Checkout session expired |
refund_exceeds_charge |
Refund amount too large |
api_key_revoked |
API key has been revoked |
Idempotency
Use the Idempotency-Key header to safely retry requests:
POST /charges
Idempotency-Key: order_12345_attempt_1
- Keys are unique per merchant
- Keys expire after 24 hours
- Duplicate requests return the original response
- Use unique keys for each distinct operation
Security Best Practices
- Never expose secret keys - Keep
sk_*keys on your server only - Verify webhook signatures - Always validate the
ForhoppPay-Signatureheader - Use HTTPS - All API communication must use TLS 1.2+
- Implement idempotency - Use
Idempotency-Keyfor all POST requests - Rotate keys regularly - Generate new keys periodically
- Monitor for anomalies - Set up alerts for unusual activity
Rate Limits & Quotas
| Resource | Limit |
|---|---|
| API Keys per Merchant | 10 |
| Webhook Endpoints per Merchant | 10 |
| Requests per Second (Live) | 100 |
| Requests per Second (Test) | 25 |
| Maximum Charge Amount | $999,999.99 |
| Checkout Session Duration | 24 hours |
| Authorized Charge Hold | 7 days |
SDK & Integrations
JavaScript SDK
<script src="https://js.forhopppay.com/v1/forhopppay.js"></script>
<script>
const forhopppay = new ForhoppPay('pk_live_xxx');
// Redirect to checkout
forhopppay.redirectToCheckout({
chargeId: 'ch_xxx'
});
</script>
npm Package
npm install @forhopppay/js
import { ForhoppPay } from '@forhopppay/js';
const forhopppay = new ForhoppPay('pk_live_xxx');
WordPress/WooCommerce
Install the ForhoppPay plugin from the WordPress plugin directory or download from your merchant dashboard.
Shopify
Install the ForhoppPay app from the Shopify App Store.
Support
- Documentation: https://docs.forhopp.com
- API Status: https://status.forhopp.com
- Support Email: support@forhopp.com
- Developer Discord: https://discord.gg/forhopppay
Last Updated: March 2026
