Gateway Management
Connect and manage multiple Stripe and PayPal accounts through the FloPay API and dashboard, including manual webhook setup.
Gateway Management
FloPay processes payments through gateway records that hold your own Stripe and PayPal account credentials. This guide walks through connecting a new account end-to-end — creating a draft, registering the provider webhook manually, saving credentials, testing the connection, and activating — plus the operational rules for managing gateways afterwards.
Two surfaces expose the same workflow with the same names and lifecycle terminology:
- REST API — the
settings/gatewaysoperations (List Gateways,Get Gateway,Create Gateway,Update Gateway,Test Gateway Connection,Activate Gateway,Deactivate Gateway). The generated REST API docs are the endpoint reference; this page is the onboarding and operations guide. - Dashboard — Settings → Gateways (
/settings/gateways), with a per-gateway detail page for credentials, webhook setup, connection testing, and lifecycle actions.
Who Can Manage Gateways
- Client owners and admins manage their own client's gateways through both surfaces. Access is always scoped to the authenticated client — another client's gateway ids read as not found.
- Members have no access. API calls return
403(Members cannot manage gateway settings.) and the dashboard hides the Settings area. - Server-to-server callers authenticating with the client identifier as the Basic username and an active user-owned API token as the password have full access — the token is scoped to that client.
- FloPay superusers use the admin mirror (
/v1/admin/settings/gateways, with an explicit target client) and select a client in the dashboard before listing or editing. The admin mirror is intentionally excluded from the public OpenAPI spec.
Accounts, Environments, and Multiple Gateways
One gateway record represents one provider account in one environment:
- Supported providers:
stripeandpaypal(providerType). - Environments:
stageandproduction(environment).stagecorresponds to Stripe test mode and the PayPal sandbox;productioncorresponds to Stripe live mode and PayPal live. A test/sandbox account and a production account are always two separate gateway records — there is no in-place switch to production. - Multiple accounts per provider are supported. A client can connect any number of distinct Stripe accounts and PayPal accounts, each as its own record with its own display name, currency, countries, and priority.
- Duplicates are rejected. Connecting the same provider account in the same environment twice fails with
409:Another gateway is already connected to provider account <id> in the <environment> environment.
During the first successful connection validation FloPay captures the canonical provider account identity (providerAccountId — the Stripe acct_… id, or the PayPal REST app client ID). From that point the gateway's identity — providerType, environment, and the connected account — is immutable. To target a different provider, environment, or account, create a new gateway.
Lifecycle
A gateway is always in one of three states (status):
| State | Meaning | Available actions |
|---|---|---|
draft | New or incomplete — not used for payments. Credentials may be partial. | Edit anything (including provider/environment while unvalidated), test, activate |
active | Complete, validated, and eligible for payment processing. | Edit FloPay settings, replace credentials, test, deactivate |
inactive | Complete but deactivated. Configuration is retained. | Edit, test, reactivate |
Rules:
- Every new gateway starts as a draft. You can save a draft with no credentials at all and finish it later.
- Activation requires completeness plus a live provider check. All three credential fields — public identifier, secret credential, and webhook verification value — must be configured, and FloPay re-validates the stored credentials with the provider at activation time. Incomplete gateways fail with
409:Activation requires a complete provider connection. Missing: <fields>. - Deactivation stops the gateway being used for new payments but keeps the record; only an
activegateway can be deactivated. - Reactivation runs the same validation path as activation — credentials are re-checked with the provider.
- Gateways are never deleted. There is no delete endpoint or dashboard action.
Existing gateways provisioned before this workflow appear as active (or inactive if they were switched off) and report as complete, without any re-validation step. They can be listed, tested, edited, and deactivated/reactivated through the same API and dashboard, and their provider/environment identity is already locked.
The Gateway Record
| Field | Writable | Notes |
|---|---|---|
name | yes | Display name, e.g. UK Ltd Stripe (live). |
providerType | drafts only | stripe or paypal. Locked after the first successful connection validation. |
environment | drafts only | stage or production. Locked after validation. |
currency | yes | 3-letter ISO 4217 code. |
countries | yes | Array of 2-letter ISO 3166-1 codes, or omitted. |
priority | yes | Non-negative integer; lower ranks first. Defaults to 0. |
publishableKey | yes | Public identifier — Stripe publishable key (pk_…) or PayPal REST app client ID. Returned in read responses. |
secretKey | yes, write-only | Stripe secret key (sk_…, or restricted rk_…) or PayPal client secret. Never returned. |
webhookSigningSecret | yes, write-only | Stripe webhook signing secret (whsec_…) or PayPal webhook ID. Never returned. |
providerAccountId | no (captured) | Canonical provider account identity, captured at validation. null until then. |
status | via lifecycle actions | draft, active, or inactive. |
code | no (generated) | FloPay-owned gateway code. |
connectionValidatedAt | no | When the provider last confirmed the stored credentials; null for unconnected drafts. |
Public identifiers vs. write-only secrets
The publishableKey is a public identifier — Stripe publishable keys and PayPal client IDs are designed to appear in frontends, and read responses return them in full.
secretKey and webhookSigningSecret are write-only. You send them once; after that, read responses expose only metadata:
secretKeyConfigured: true | falsewebhookSigningSecretConfigured: true | falseupdatedAt
There is no way to retrieve a secret after submission — not through the API, the dashboard, or FloPay support. The dashboard shows secret inputs as always-blank password fields with a "Configured — enter a new value to replace it." hint. If a secret is lost, generate a new one at the provider and submit the replacement.
To replace a credential, send the new value in an ordinary update request (PATCH on the API, or type into the blank secret field and save in the dashboard). Omitted credential fields keep their stored values. A credential-bearing update is atomic: FloPay validates the complete resulting credential set with the provider before saving anything — if validation fails, the stored configuration is untouched and you get a sanitized, actionable error.
Never place real secret keys, client secrets, or signing secrets in code samples, screenshots, URLs, logs, or support tickets. All examples below use placeholders.
The FloPay Webhook Callback URL
Phase 1 does not create provider webhooks automatically — you register them manually in each provider's dashboard, then give FloPay the verification value (Stripe signing secret or PayPal webhook ID).
FloPay exposes one shared inbound endpoint per provider:
- Stripe:
https://<flopay-webhook-host>/webhooks/stripe - PayPal:
https://<flopay-webhook-host>/webhooks/paypal
The URL is per provider, not per gateway — deliveries are matched to your gateway by the account identity in the event payload, so every Stripe account you connect registers the same Stripe callback URL. The webhook host differs between FloPay's stage and production environments; copy the exact URL from the Webhook setup card on the gateway's dashboard detail page rather than constructing it by hand.
Connecting a Stripe Gateway
1. Create a draft
In the dashboard, open Settings → Gateways → Add gateway, choose provider Stripe and the environment, and create the draft. Via the API, POST /v1/settings/gateways (see API examples). Provider and environment stay editable while the draft is unvalidated.
2. Obtain the API keys
In the Stripe Dashboard → Developers → API keys, copy:
- the publishable key —
pk_test_…(test mode) orpk_live_…(live mode) → FloPay'spublishableKey - the secret key —
sk_test_…/sk_live_…, or a restricted keyrk_test_…/rk_live_…with account read access → FloPay'ssecretKey
Match the environments. A stage gateway requires test-mode keys and a production gateway requires live-mode keys — mixed-mode credentials are rejected at validation with an explicit prefix error.
3. Register the webhook manually
- In the Stripe Dashboard, open Developers → Webhooks and add a destination — in the same mode (test/live) as the keys.
- Paste the FloPay Stripe callback URL from the gateway's Webhook setup card as the endpoint URL.
- Subscribe the endpoint to the Stripe events FloPay consumes — the full list is in Stripe webhook events.
- Copy the endpoint's signing secret (
whsec_…) → FloPay'swebhookSigningSecret.
4. Save the credentials
Submit publishableKey, secretKey, and webhookSigningSecret on the draft — in the dashboard form, or via PATCH. Because the request carries secrets, FloPay validates the full credential set with Stripe before saving and captures your Stripe account id (acct_…) as providerAccountId.
5. Test the connection
Run Test connection in the dashboard, or POST /v1/settings/gateways/:id/test. The test probes Stripe with the stored credentials without changing the gateway and reports success plus the account id, or a sanitized error.
6. Activate
Run Activate. FloPay checks completeness (all three credential fields), re-validates with Stripe, and moves the gateway to active. It is now eligible for payment processing.
Connecting a PayPal Gateway
1. Create a draft
Same as Stripe: Settings → Gateways → Add gateway with provider PayPal, or POST /v1/settings/gateways with "providerType": "paypal". Use stage for a sandbox app and production for a live app.
2. Obtain the REST app credentials
In the PayPal developer dashboard, open (or create) the REST API app for the matching environment — a sandbox app for a stage gateway, a live app for a production gateway — and copy:
- the client ID → FloPay's
publishableKey - the client secret → FloPay's
secretKey
3. Register the webhook manually
- On the same PayPal REST app, add a webhook.
- Paste the FloPay PayPal callback URL from the gateway's Webhook setup card as the webhook URL.
- Subscribe to the PayPal event types FloPay consumes — the full list is in PayPal webhook events.
- After registration PayPal displays a webhook ID → FloPay's
webhookSigningSecret.
For PayPal, webhookSigningSecret stores the webhook ID, not an HMAC secret — FloPay uses it to verify deliveries through PayPal's signature-verification endpoint. The field name is provider-neutral.
4. Save the credentials
Submit publishableKey (client ID), secretKey (client secret), and webhookSigningSecret (webhook ID) on the draft. FloPay authenticates against PayPal sandbox or live as appropriate, verifies the webhook ID is registered on the account, and captures the canonical account identity.
5. Test the connection
Test connection / POST /v1/settings/gateways/:id/test probes PayPal with the stored credentials without mutating the gateway.
6. Activate
Activate checks completeness, re-validates against PayPal, and moves the gateway to active.
API Examples
All examples use client Basic authentication: $FLOPAY_CLIENT_ID is the client identifier and username, while $FLOPAY_API_TOKEN is the active user-owned API token and password. Owner/admin OAuth bearer tokens work the same way. Values like $FLOPAY_API_TOKEN and pk_live_PLACEHOLDER are placeholders — never paste real secrets into shared examples.
List and get
curl https://api.flopay.com/v1/settings/gateways \
-u "$FLOPAY_CLIENT_ID:$FLOPAY_API_TOKEN"
curl https://api.flopay.com/v1/settings/gateways/1c9e4a7e-5b2d-4f6a-9c3e-8d1f2b3a4c5d \
-u "$FLOPAY_CLIENT_ID:$FLOPAY_API_TOKEN"A read response returns full public metadata but only …Configured booleans for secret fields:
{
"id": "1c9e4a7e-5b2d-4f6a-9c3e-8d1f2b3a4c5d",
"clientId": "7a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
"name": "UK Ltd Stripe (live)",
"code": "gw_9f2c4d6e8a0b4c2d",
"providerType": "stripe",
"environment": "production",
"status": "active",
"currency": "GBP",
"countries": ["GB", "IE"],
"priority": 0,
"providerAccountId": "acct_PLACEHOLDER",
"publishableKey": "pk_live_PLACEHOLDER",
"secretKeyConfigured": true,
"webhookSigningSecretConfigured": true,
"connectionValidatedAt": "2026-07-01T10:15:00.000Z",
"createdAt": "2026-06-28T09:00:00.000Z",
"updatedAt": "2026-07-01T10:15:00.000Z"
}Create an incomplete draft
Credentials are optional at creation — this draft has none yet:
curl -X POST https://api.flopay.com/v1/settings/gateways \
-u "$FLOPAY_CLIENT_ID:$FLOPAY_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "UK Ltd Stripe (live)",
"providerType": "stripe",
"environment": "production",
"currency": "GBP",
"countries": ["GB", "IE"],
"priority": 0
}'The response is a draft with providerAccountId: null, secretKeyConfigured: false, and webhookSigningSecretConfigured: false.
Update ordinary fields
Plain settings updates never touch credentials:
curl -X PATCH https://api.flopay.com/v1/settings/gateways/1c9e4a7e-5b2d-4f6a-9c3e-8d1f2b3a4c5d \
-u "$FLOPAY_CLIENT_ID:$FLOPAY_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "UK Ltd Stripe (GBP, live)",
"countries": ["GB"],
"priority": 1
}'Replace credentials
Credential fields are optional on the same PATCH — send only what you are replacing, and omitted secrets stay as they are. This request rotates the secret key and signing secret while keeping the publishable key:
curl -X PATCH https://api.flopay.com/v1/settings/gateways/1c9e4a7e-5b2d-4f6a-9c3e-8d1f2b3a4c5d \
-u "$FLOPAY_CLIENT_ID:$FLOPAY_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"secretKey": "sk_live_PLACEHOLDER",
"webhookSigningSecret": "whsec_PLACEHOLDER"
}'FloPay validates the complete resulting credential set with the provider before saving. On success the response reflects only metadata — secretKeyConfigured: true, a fresh updatedAt — never the submitted values. On failure nothing is stored and the previous credentials remain in effect.
For PayPal the same fields carry the client ID (publishableKey), client secret (secretKey), and webhook ID (webhookSigningSecret).
Test the connection
curl -X POST https://api.flopay.com/v1/settings/gateways/1c9e4a7e-5b2d-4f6a-9c3e-8d1f2b3a4c5d/test \
-u "$FLOPAY_CLIENT_ID:$FLOPAY_API_TOKEN"{
"success": true,
"providerAccountId": "acct_PLACEHOLDER",
"error": null
}The probe never mutates the gateway and never carries key material. On failure, success is false and error contains the sanitized provider message (see Troubleshooting).
Activate and deactivate
curl -X POST https://api.flopay.com/v1/settings/gateways/1c9e4a7e-5b2d-4f6a-9c3e-8d1f2b3a4c5d/activate \
-u "$FLOPAY_CLIENT_ID:$FLOPAY_API_TOKEN"
curl -X POST https://api.flopay.com/v1/settings/gateways/1c9e4a7e-5b2d-4f6a-9c3e-8d1f2b3a4c5d/deactivate \
-u "$FLOPAY_CLIENT_ID:$FLOPAY_API_TOKEN"Both return the updated gateway record. Reactivating an inactive gateway uses the same activate endpoint and re-validates credentials with the provider.
Troubleshooting
Errors are sanitized — they describe what to fix without echoing credentials. Common cases:
| Problem | Typical error | Fix |
|---|---|---|
| Invalid Stripe credentials | 422 — Stripe rejected the API key. Check the key belongs to this account and environment and has not been revoked. | Re-copy the secret key from the Stripe account, confirm it hasn't been rolled, and resubmit. |
| Stripe key permissions | 422 — The Stripe API key does not have permission to read the account. Use a secret key or a restricted key with account read access. | Use the standard secret key, or grant the restricted key account read access. |
| Invalid PayPal credentials | 422 — PayPal rejected the client credentials for the production (live) environment. Check the client ID and secret, and that they belong to this environment. | Confirm client ID and secret come from the same REST app, and that the app matches the gateway's environment. |
| Environment mismatch | 422 — e.g. A production gateway requires a Stripe live-mode secret key (sk_live_ or rk_live_…). | Use test-mode keys/sandbox apps on stage gateways and live-mode keys/live apps on production gateways. Moving to production means creating a new gateway. |
| Duplicate provider account | 409 — Another gateway is already connected to provider account <id> in the <environment> environment. | The account is already connected. Manage the existing gateway instead, or connect a genuinely different account. |
| Missing webhook configuration | 409 on activate — Activation requires a complete provider connection. Missing: webhookSigningSecret. | Register the webhook in the provider dashboard (Stripe / PayPal) and save the signing secret or webhook ID. |
| Unrecognized PayPal webhook ID | 422 — PayPal does not recognize the supplied webhook ID on this account. Register the webhook in the PayPal developer dashboard and copy its ID. | Copy the webhook ID from the REST app that owns the credentials, in the matching environment. |
| Editing locked identity fields | 409 — Provider and environment are locked once a connection has been validated. Create a new gateway to target a different provider, environment, or account. | Identity is immutable after validation — create a new gateway record. |
| Swapping the connected account | 409 — This gateway is locked to provider account <id>. Connect a different account through a new gateway. | Credentials must belong to the originally validated account. A different account needs its own gateway. |
| Failed connection test | success: false with a sanitized error | Read the error — it identifies the credential or environment problem without exposing values — fix the credential at the provider, and update the gateway. |
| Credential update seems lost | Update returned 422 | Failed validation rolls back atomically: the previous credentials remain stored and in effect. Fix the new values and resubmit; nothing was partially applied. |
| Deactivate rejected | 409 — Only an active gateway can be deactivated. | Drafts can't be deactivated — they are already not in use. |
| No access | 403 — Members cannot manage gateway settings. | Ask a client owner/admin to make the change, or have your role upgraded. |
Contacting support: share the gateway id, code, providerType, environment, status, timestamps, and the exact sanitized error text. Never share secret keys, client secrets, or signing secrets — FloPay support will never ask for them, and FloPay cannot read the ones you have stored.
Related
- REST API docs — generated OpenAPI reference for the
settings/gatewaysoperations - Stripe webhook events — inbound Stripe events to subscribe the webhook endpoint to
- PayPal webhook events — inbound PayPal events to subscribe the webhook to
- Direct PayPal — how an active PayPal gateway changes checkout rendering
- Cascading Processing — how multiple active gateways are used at checkout