HCP Registration, Gateway & WAF Best Practices
The HealthSafePay Cloud Platform (HCP) is your secure gateway to Convenient Checkout APIs. This guide covers:
- How to register and authenticate with HCP
- How the HCP Gateway and Azure WAF protect your integration
- Best practices to avoid common WAF/API issues
1. HCP Registration & API Authenticationβ
Convenient Checkout APIs are available through HCP for merchants, partners, and internal users.
Registration Stepsβ
- Visit the HCP site and review onboarding for the Commerce package.
- Register your application in HCP and request access to CCG APIs with the required scopes (API Access Levels).
- Configure API access: After approval, use your client credentials (ID/secret) for authentication.
- Explore the HCP Console to manage clients, keys, and API usage.
- Browse the API Catalog for available APIs and docs.
- STAGE:
rg-common-checkout-nonprod(non-prod) - PROD:
rg-common-checkout-prod(production)
2. HCP Gateway & WAF: What to Watch Forβ
The HCP Gateway uses Azure Web Application Firewall (WAF) to protect your APIs. Some requests may be blocked if they donβt follow best practices.
| Scenario | Impact | How to Fix |
|---|---|---|
| URLs in POST body not encoded | Request blocked | Percent-encode all URLs in POST bodies |
GET with Transfer-Encoding header | Request blocked | Never send this header on GET |
Missing Accept header | Request blocked | Always send Accept on GET |
| Other WAF triggers | Request blocked | See best practices below |
3. Common WAF Block Scenariosβ
1. URLs in POST Body (Encoding Required)
Example fields:
config.privacypolicyurlappearance.font.fontSources.cssSrcappearance.merchantlogo
Remediation: Always percent-encode URLs in POST request bodies.
2. GET Requests with Transfer-Encoding Header
Including this header on GET requests will trigger the WAF and block the request.
Remediation: Never include Transfer-Encoding on GET requests.
3. Missing Accept Header
Azure WAF blocks GET requests that do not include an Accept header. This affects endpoints like:
/token/setup-payment-methods/sessions/payments/{payment_id}/customers/{customer_id}/payment-methods/payment-methods/search
Remediation: Always include an Accept header on GET requests.
4. Other Best Practices
- GET or HEAD requests should not have a body
- POST requests must have a valid JSON body
- Avoid SQL characters in request bodies
- Encode all URLs in request bodies
4. Best Practices for API Securityβ
- Store client credentials and API keys securely
- Rotate secrets regularly
- Use least-privilege API scopes (see access levels)
- Monitor API usage and set up alerts for unusual activity
5. Troubleshooting & Supportβ
- Splunk: HCP Gateway WAF Blocks (Non-Prod)
- Azure WAF Rule Set Reference
- HCP Team for registration/auth issues
- Contact your HCP administrator or support team
β Quick Checklistβ
- Register and onboard in HCP
- Request correct API scopes
- Store credentials securely
- Encode all URLs in POST bodies
- Never send
Transfer-Encodingon GET - Always send
Accepton GET - No body on GET/HEAD
- POST body is valid JSON
- No SQL characters in request bodies
For further information about HCP, visit HCP site
6. Updating the HCP API Gateway YAML Specβ
When endpoints are added or changed, the HCP Stargate Gateway YAML must be updated and re-submitted to the HCP Console under API Management.
6.1 Deployed Endpointsβ
Not all API endpoints are routed through HCP. Understanding the distinction is important when registering APIs, debugging gateway issues, or adding new endpoints.
HCP Gateway vs Virtual Serviceβ
| HCP Stargate Gateway | Virtual Service | |
|---|---|---|
| Who calls it | Merchant server / backend integrations | CCG Widget (browser, user-initiated) |
| Token scope | merchant, merchant-pci, or merchant-wallet-management | user |
| Auth enforced by | HCP gateway policy | nginx + internal auth middleware |
| Registered in HCP Console | Yes β YAML spec must be uploaded | No β never submitted to HCP |
| CORS | Not applicable | Enforced by nginx for widget origins |
| WAF protection | Azure WAF via HCP | nginx only |
| Server block in apispec | ccgStageServer / ccgProdServer | nginxServer / prodnginxServer |
| Path prefix | No prefix (e.g. /payments) | /v2/ prefix (e.g. /v2/checkout-sessions/...) |
A new endpoint belongs in the HCP YAML if its servers: block references ccgStageServer or ccgProdServer. If it references nginxServer or prodnginxServer, it is virtual and should not be submitted to HCP.
HCP Stargate Gateway endpoints and nginx virtual service endpoints are listed separately for each API version below.
HCP Gateway Endpoints (v1)β
| Method | Path | Domain | Scope | Operation ID |
|---|---|---|---|---|
GET | /payments | Payments | merchant, user | getPaymentIntentByMerchantId |
POST | /payments | Payments | merchant, user | createPaymentIntent |
GET | /payments/{paymentId} | Payments | merchant, user | getPaymentIntent |
PATCH | /payments/{paymentId}/cancel | Payments | merchant | cancelPayment |
PATCH | /payments/{paymentId}/capture | Payments | merchant | capturePayment |
PATCH | /payments/{paymentId}/confirm | Payments | user | confirmPayment |
POST | /refunds | Payments | merchant | createRefund |
GET | /refunds/{refund-id} | Payments | merchant | getRefund |
POST | /sessions | Sessions | merchant | createSession |
GET | /sessions/{session-id} | Sessions | merchant | getSession |
POST | /token/payments | Payments (Token) | merchant-pci | createPaymentUsingToken |
POST | /token/setup-payment-methods | Customers (Token) | merchant-pci | createCustomerAndSetupPaymentMethod |
GET | /token/setup-payment-methods/{setup-payment-method-id} | Customers (Token) | merchant-pci | getSetupPaymentMethodByIdPCIFlow |
POST | /payment-methods/search | Customers | merchant, merchant-wallet-management | getPaymentMethodsSearch |
GET | /payment-methods/{payment-method-id} | Customers | user, merchant-wallet-management | getPaymentMethod |
PATCH | /payment-methods/{payment-method-id} | Customers | user, merchant-wallet-management | updatePaymentMethod |
DELETE | /payment-methods/{payment-method-id} | Customers | user, merchant-wallet-management | deletePaymentMethod |
GET | /customers/{id}/payment-methods | Customers | user | getPaymentMethods-user |
GET | /customers/{id}/payment-methods/{payment-method-id} | Customers | user | getPaymentMethod-user |
PATCH | /customers/{id}/payment-methods/{payment-method-id} | Customers | merchant, user | updatePaymentMethod-user |
DELETE | /customers/{id}/payment-methods/{payment-method-id} | Customers | user | deletePaymentMethod-user |
POST | /customers/{id}/setup-payment-methods | Customers | user | createSetupPaymentMethod |
GET | /customers/{id}/setup-payment-methods/{setup-payment-method-id} | Customers | user | getSetupPaymentMethodById |
GET | /banks/routing/{routing-number} | ACH | user | getBankByRotuingNumber |
Virtual Service Endpoints β v1 (nginx β not submitted to HCP)β
| Method | Path | Domain | Notes |
|---|---|---|---|
POST | /checkout-sessions | Checkout Sessions | Widget-initiated |
GET | /checkout-sessions/{sessionId} | Checkout Sessions | Widget-initiated |
PATCH | /checkout-sessions/{sessionId}/cancel | Checkout Sessions | Widget-initiated |
POST | /checkout-sessions/{sessionId}/child-sessions | Checkout Sessions | Widget-initiated |
POST | /api-ccg/payments | Payments | Widget-initiated |
GET | /api-ccg/payments/{paymentId} | Payments | Widget-initiated |
GET | /api-ccg/payments/{paymentId}/confirm | Payments | Widget-initiated |
POST | /api-ccg/customers/{id}/setup-payment-methods | Customers | Widget-initiated |
GET | /api-ccg/customers/{id}/setup-payment-methods/{setup-payment-method-id} | Customers | Widget-initiated |
GET | /api-ccg/customers/{id}/payment-methods | Customers | Widget-initiated |
GET | /api-ccg/customers/{id}/payment-methods/{payment-method-id} | Customers | Widget-initiated |
PATCH | /api-ccg/customers/{id}/payment-methods/{payment-method-id} | Customers | Widget-initiated |
DELETE | /api-ccg/customers/{id}/payment-methods/{payment-method-id} | Customers | Widget-initiated |
GET | /api-ccg/customers/banks/routing/{routingNumber} | ACH | Widget-initiated |
HCP Gateway Endpoints (v2)β
| Method | Path | Domain | Scope | Operation ID |
|---|---|---|---|---|
GET | /payments | Payments | merchant, user | getPaymentIntentByMerchantId |
POST | /payments | Payments | merchant, user | createPaymentIntent |
GET | /payments/{paymentId} | Payments | merchant, user | getPaymentIntent |
PATCH | /payments/{paymentId}/cancel | Payments | merchant | cancelPayment |
PATCH | /payments/{paymentId}/capture | Payments | merchant | capturePayment |
PATCH | /payments/{paymentId}/confirm | Payments | user | confirmPayment |
POST | /refunds | Payments | merchant | createRefund |
GET | /refunds/{refund-id} | Payments | merchant | getRefund |
POST | /sessions | Sessions | merchant | createSession |
GET | /sessions/{session-id} | Sessions | merchant | getSession |
POST | /token/payments | Payments (Token) | merchant-pci | createPaymentIntentRequest |
POST | /token/setup-payment-methods | Customers (Token) | merchant-pci | createCustomerAndSetupPaymentMethod |
GET | /token/setup-payment-methods/{setup-payment-method-id} | Customers (Token) | merchant-pci | getSetupPaymentMethodByIdPCIFlow |
POST | /payment-methods/search | Customers | merchant, merchant-wallet-management | getPaymentMethodsSearch |
GET | /payment-methods/{payment-method-id} | Customers | user, merchant-wallet-management | getPaymentMethod |
PATCH | /payment-methods/{payment-method-id} | Customers | user, merchant-wallet-management | updatePaymentMethod |
DELETE | /payment-methods/{payment-method-id} | Customers | user, merchant-wallet-management | deletePaymentMethod |
GET | /customers/{id}/payment-methods | Customers | user | getPaymentMethods-user |
GET | /customers/{id}/payment-methods/{payment-method-id} | Customers | user | getPaymentMethod-user |
PATCH | /customers/{id}/payment-methods/{payment-method-id} | Customers | merchant, user | updatePaymentMethod-user |
DELETE | /customers/{id}/payment-methods/{payment-method-id} | Customers | user | deletePaymentMethod-user |
POST | /customers/{id}/setup-payment-methods | Customers | user | createSetupPaymentMethod |
GET | /customers/{id}/setup-payment-methods/{setup-payment-method-id} | Customers | user | getSetupPaymentMethodById |
GET | /banks/routing/{routing-number} | ACH | user | getBankByRoutingNumber |
Virtual Service Endpoints β v2 (nginx β not submitted to HCP)β
| Method | Path | Domain | Notes |
|---|---|---|---|
GET | /v2/checkout-sessions/{sessionId} | Checkout Sessions | Widget-initiated |
PATCH | /v2/checkout-sessions/{sessionId} | Checkout Sessions | Widget-initiated |
PATCH | /v2/checkout-sessions/{sessionId}/cancel | Checkout Sessions | Widget-initiated |
POST | /v2/checkout-sessions/{sessionId}/child-sessions | Checkout Sessions | Widget-initiated |
POST | /v2/api-ccg/payments | Payments | Widget-initiated |
GET | /v2/api-ccg/payments/{paymentId} | Payments | Widget-initiated |
POST | /v2/payments/{paymentId}/capture | Payments | Split-tender capture β planned, not yet implemented |
6.2 V1 β V2 Changes Summaryβ
| Category | Change |
|---|---|
| New path | None β v2 HCP endpoints are a 1:1 match with v1 |
| Renamed operation | POST /token/payments: createPaymentUsingToken β createPaymentIntentRequest |
| Renamed operation | GET /banks/routing/{routing-number}: fixed typo getBankByRotuingNumber β getBankByRoutingNumber |
| New response codes | 401 and 403 now declared on all protected operations |
| New header | X-Upstream-Env added to all operations |
| Security scope prefix | financial/commerce/nonprodcheckout:* (non-prod) / financial/commerce/checkout:* (prod) |
| Backend host | Changed from api-v1.healthsafepay.com to api-v2.healthsafepay.com per environment |
| Removed | DummyRequest schema replaced with domain-named schemas (CancelCheckoutSessionRequest, etc.) |
6.3 Update Processβ
Step 1 β Open HCP Consoleβ
Go to https://console.hcp.uhg.com/ β API Management β select the correct Resource Group for the target environment:
| Environment | Resource Group |
|---|---|
| dev, perf, reg, test | rg-common-checkout-nonprod |
| stage | rg-common-checkout-nonprod |
| prod | rg-common-checkout-prod |
Step 2 β Edit the source YAMLβ
Source YAMLs and the generation script live in the hcp-api repository:
hcp-api/
dev/ *-dev-v2.yaml # Source YAML (reference)
perf/ *-perf-v2.yaml
reg/ *-reg-v2.yaml
stage/ *-stage-v2.yaml
test/ *-test-v2.yaml
prod/ *-checkout-v2.yaml
The dev source is the reference for paths: and components:. All other environments share the same paths but have their own x-instance: block (backend host, CORS origins). Never overwrite env-specific fields when syncing from dev.
Step 3 β Generate the submission fileβ
From the source YAML (e.g. dev/*-dev-v2.yaml), produce a submission file that contains only the spec: block β strip the outer kind:, metadata:, and status: gateway wrapper. The resulting *-updated.yaml must pass all HCP MUST Rules before upload.
Step 4 β Apply to the HCP portalβ
In the HCP Console, select the API resource for the target environment and upload the *-updated.yaml file. Deploy the new version and verify routing with a smoke test.
Step 5 β Propagate to remaining environmentsβ
Repeat Steps 2β4 for each environment. Each env's *-updated.yaml is submitted independently.
6.4 HCP MUST Rulesβ
The submission file must satisfy all of the following rules before it can be accepted by HCP:
| Rule | What to check |
|---|---|
Every POST / PUT / PATCH must have a requestBody | Include required: false with a domain-named schema even when no body is needed |
requestBody.content.application/json.schema must resolve | The $ref must exist in components/schemas |
Every operation must have an operationId | camelCase, matching the Java controller method name |
Every operation must have security | At least one scope (merchant, user, or merchant-pci) |
| Every operation must declare a 2xx response | At least one of 200 / 201 / 202 |
If the controller method has no @RequestBody (e.g., cancel by path param only), you must still declare a requestBody with required: false and a domain-named schema. Do not use generic names like DummyRequest.
requestBody:
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/CancelCheckoutSessionRequest'
# In components/schemas:
CancelCheckoutSessionRequest:
type: object
description: >
No fields required. Session identified by path param and X-Merchant-Id header.
Present to satisfy the HCP PATCH requestBody requirement.
properties: {}
6.5 Per-Environment Referenceβ
| Environment | Backend Host | CORS Origin | Resource Group |
|---|---|---|---|
| dev | dev-api-v2.healthsafepay.com | dev-wallet.healthsafepay.com | rg-common-checkout-nonprod |
| perf | perf-api-v2.healthsafepay.com | perf-wallet.healthsafepay.com | rg-common-checkout-nonprod |
| reg | reg-api-v2.healthsafepay.com | reg-wallet.healthsafepay.com | rg-common-checkout-nonprod |
| stage | stg-api-v2.healthsafepay.com | stg-wallet.healthsafepay.com | rg-common-checkout-nonprod |
| test | test-api-v2.healthsafepay.com | test-wallet.healthsafepay.com | rg-common-checkout-nonprod |
| prod | api-v2.healthsafepay.com | wallet.healthsafepay.com | rg-common-checkout-prod |