Custom Provider Integrations — Evoxup :root{ --bg:#fff;--soft:#f6f8fc;--ink:#0a1222;--muted:#5e6c82;--line:#dfe7f2; --blue:#1769ff;--blue2:#0f50c1;--blue3:#0a2d70;--red:#d7263d;--dark:#07111f; --green:#16834c;--amber:#a46c00;--purple:#6847bd;--shadow:0 18px 50px rgba(20,62,125,.10) } *{box-sizing:border-box} html{scroll-behavior:smooth} body{margin:0;font-family:Inter,ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;color:var(--ink);background:var(--bg);line-height:1.72} a{color:inherit;text-decoration:none} .container{width:min(1200px,calc(100% - 40px));margin:auto} h1,h2,h3,h4{line-height:1.13;margin:0 0 16px} h1{font-size:clamp(3rem,6vw,5.8rem);letter-spacing:-.055em} h2{font-size:clamp(2rem,4vw,3.6rem);letter-spacing:-.045em} h3{font-size:1.35rem} p{margin:0 0 18px;color:var(--muted)} .lead{font-size:clamp(1.08rem,1.6vw,1.32rem);max-width:900px} .eyebrow{display:inline-flex;align-items:center;gap:9px;font-size:.76rem;font-weight:900;letter-spacing:.13em;text-transform:uppercase;color:var(--blue)} .eyebrow:before{content:"";width:28px;height:2px;background:var(--red)} .btn{display:inline-flex;align-items:center;justify-content:center;min-height:48px;padding:0 20px;border-radius:12px;font-weight:850;border:1px solid transparent} .btn.primary{background:var(--blue);color:#fff}.btn.secondary{background:#fff;border-color:var(--line)} .badge{display:inline-flex;padding:5px 10px;border-radius:999px;font-size:.68rem;font-weight:900;background:#eaf1ff;color:var(--blue2)} header{position:sticky;top:0;z-index:20;background:rgba(255,255,255,.93);backdrop-filter:blur(16px);border-bottom:1px solid var(--line)} .nav{height:72px;display:flex;align-items:center;justify-content:space-between;gap:20px} .brand{display:flex;align-items:center;gap:10px;font-weight:900} .brandmark{width:34px;height:34px;border-radius:11px;background:linear-gradient(145deg,var(--blue),var(--blue3));position:relative} .brandmark:after{content:"";position:absolute;width:10px;height:10px;border-radius:50%;background:var(--red);right:-3px;bottom:4px;border:3px solid white} .navlinks{display:flex;gap:22px;font-size:.92rem;font-weight:750;color:#33445e} .navright{display:flex;gap:10px} .hero{padding:100px 0 72px;background: radial-gradient(circle at 84% 8%,rgba(23,105,255,.14),transparent 28%), radial-gradient(circle at 8% 28%,rgba(215,38,61,.06),transparent 20%), linear-gradient(180deg,#fff,#f8fbff)} .hero-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:54px;align-items:center} .actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:26px} .console{background:linear-gradient(150deg,#07111f,#102b60);border-radius:28px;padding:28px;color:#fff;box-shadow:0 30px 80px rgba(7,17,31,.24)} .console p{color:#b8c8df} .consolebox{background:#091728;border:1px solid #263f67;border-radius:16px;padding:16px;margin-top:18px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.83rem;color:#d9e7ff} .consoleline{padding:6px 0;border-bottom:1px solid rgba(255,255,255,.06)}.consoleline:last-child{border-bottom:0} .k{color:#88b7ff}.v{color:#cfe1ff}.ok{color:#71d39a} section{padding:90px 0}.soft{background:var(--soft)}.dark{background:linear-gradient(135deg,#07111f,#0a1e3c);color:#fff} .dark h2,.dark h3,.dark h4{color:#fff}.dark p{color:#aebdd2} .content-layout{display:grid;grid-template-columns:270px 1fr;gap:38px;align-items:start} .toc{position:sticky;top:95px;border:1px solid var(--line);border-radius:18px;background:#fff;padding:16px} .toc strong{display:block;font-size:.72rem;text-transform:uppercase;letter-spacing:.08em;color:#8090a8;padding:7px 9px} .toc a{display:block;padding:9px 10px;border-radius:9px;color:#465872;font-weight:700;font-size:.88rem} .toc a:hover{background:#edf3ff;color:var(--blue)} .article{min-width:0}.article>section{padding:0 0 72px}.article h2{font-size:2.35rem}.article h3{margin-top:28px} .callout{padding:18px 20px;border-left:4px solid var(--blue);background:#f1f6ff;border-radius:10px;color:#42536d;margin:20px 0} .warn{border-left-color:var(--red);background:#fff3f5;color:#7d3340} .good{border-left-color:var(--green);background:#eefaf3;color:#37634b} .tablewrap{overflow:auto;border:1px solid var(--line);border-radius:18px;background:#fff;margin:20px 0} table{width:100%;border-collapse:collapse;min-width:900px} th,td{padding:14px 16px;border-bottom:1px solid #edf1f7;text-align:left;vertical-align:top} th{background:#f7f9fd;font-size:.77rem;text-transform:uppercase;letter-spacing:.05em;color:#40516a} td{color:#52627a;font-size:.92rem} .arch{padding:24px;border-radius:20px;background:#091523;color:#fff;margin:22px 0} .archgrid{display:grid;grid-template-columns:repeat(7,1fr);gap:8px;align-items:center} .anode{padding:16px 10px;border:1px solid #29466f;border-radius:13px;background:#0f213c;text-align:center} .anode strong{display:block;font-size:.87rem}.anode small{color:#9ab0cf;font-size:.72rem} .arrow{text-align:center;font-weight:900;color:#8ba2c5} .matrix{display:grid;grid-template-columns:repeat(2,1fr);gap:18px;margin-top:18px} .box{padding:22px;border:1px solid var(--line);border-radius:18px;background:#fff} .box strong{display:block;margin-bottom:7px} .code{background:#0b1524;color:#d9e7ff;border-radius:14px;padding:18px;overflow:auto;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.87rem;white-space:pre-wrap} .steps{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:20px} .step{padding:20px;border:1px solid var(--line);border-radius:17px;background:#fff} .stepnum{width:38px;height:38px;border-radius:11px;background:#edf3ff;color:var(--blue);display:grid;place-items:center;font-weight:900;margin-bottom:13px} .scenario{border:1px solid var(--line);border-radius:20px;background:#fff;margin:22px 0;overflow:hidden} .scenario-head{padding:18px 22px;background:#f8faff;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;gap:15px;align-items:center} .scenario-body{padding:22px} .flowline{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin:18px 0} .flowitem{padding:15px;border:1px solid var(--line);border-radius:13px;background:#fff;text-align:center} .flowitem strong{display:block;font-size:.9rem}.flowitem small{color:#7b899f} .security-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px} .sec{padding:22px;border-radius:18px;background:#0c1b32;border:1px solid #1d3457} .sec strong{display:block;color:#fff;margin-bottom:7px}.sec p{margin:0} .fields{display:grid;grid-template-columns:repeat(2,1fr);gap:18px} .fieldcard{padding:22px;border:1px solid var(--line);border-radius:18px;background:#fff} .fieldcard code{background:#edf3ff;color:var(--blue2);padding:2px 6px;border-radius:6px} .faq details{border:1px solid var(--line);border-radius:14px;padding:17px 19px;background:#fff;margin-bottom:10px} .faq summary{font-weight:850;cursor:pointer}.faq p{margin:12px 0 0} .cta{padding:82px 0;background:linear-gradient(135deg,#07111f,#102b5c);color:#fff} .cta h2{color:#fff}.cta p{color:#bccbe0} footer{background:#050b14;color:#9fb0c8;padding:52px 0 25px} .footgrid{display:grid;grid-template-columns:1.4fr repeat(4,1fr);gap:28px} footer h4{color:#fff;margin:0 0 12px}footer a{display:block;margin:7px 0;font-size:.88rem} .footnote{border-top:1px solid #172238;margin-top:30px;padding-top:18px;font-size:.8rem;color:#75859e} @media(max-width:980px){ .navlinks{display:none}.hero-grid,.content-layout{grid-template-columns:1fr}.toc{position:static}.archgrid{grid-template-columns:1fr}.arrow{transform:rotate(90deg)} .matrix,.fields{grid-template-columns:1fr}.steps,.security-grid{grid-template-columns:repeat(2,1fr)}.flowline{grid-template-columns:1fr}.footgrid{grid-template-columns:repeat(2,1fr)} } @media(max-width:640px){ .container{width:min(100% - 26px,1200px)}h1{font-size:3rem}section{padding:68px 0}.steps,.security-grid{grid-template-columns:1fr}.footgrid{grid-template-columns:1fr}.navright a:first-child{display:none} } img,svg{display:block;max-width:100%} .brand-mark svg{width:23px;height:23px;color:#fff} .brand-mark{ width:38px;height:38px;border-radius:12px; background:linear-gradient(145deg,var(--blue),var(--teal)); display:grid;place-items:center;box-shadow:0 8px 24px rgba(18,84,244,.24); }
Custom Provider Solution

Connect a Commerce Provider Evoxup Has Never Seen Before.

Define how the provider sends events, how Evoxup authenticates, how transactions are verified, how products are identified, and how provider data is normalized into the same internal fulfillment pipeline used by every other integration.

CUSTOM PROVIDER

Describe the Provider. Keep Core Stable.

The custom integration layer translates external behavior into Evoxup's internal event model.

transport: webhook + api
auth: bearer token
verification: api_lookup
product_id_path: data.product.id
transaction_id_path: data.order.id
mapping: enabled
Definition

What a Custom Provider Is — and Is Not

A Custom Provider is a provider-neutral integration definition for a commerce platform that does not have a ready-made Evoxup profile.

It tells Evoxup how to communicate with the provider without changing the Core membership, licensing or entitlement architecture.

Custom Provider is responsible for

Transport, credentials, verification, event parsing, product identity and provider-specific API behavior.

Core remains responsible for

Internal products, mapping, membership, license authority, entitlement, duplicate protection and fulfillment records.

Core principle: adding a new provider should extend the integration boundary, not create a second membership or licensing system.
Architecture

The Custom Provider Sits Before the Internal Business Logic

ProviderWebhook/API
→
AuthenticateCredential layer
→
VerifyTrust policy
→
NormalizeInternal event
↓
Identify ProductExternal ID
→
MapEVO Product
→
FulfillMembership / License
→
RecordResult / duplicate guard

This separation is what allows Evoxup to support additional providers without embedding every provider's payload format into the fulfillment engine.

Integration Contract

Define the Provider Before Writing Business Rules

A robust Custom Provider configuration should describe the provider's behavior explicitly.

Provider identity

Internal slug, display name and environment information.

provider_slug
Webhook endpoint

Where the external platform sends sale or order events.

webhook_path
API base URL

Base endpoint for verification, discovery or synchronization.

api_base_url
Authentication type

Bearer token, API key, Basic auth or another supported mechanism.

auth_mode
Verification policy

Signature, HMAC, API lookup, authenticated callback or another supported policy.

verification_mode
Product identifier path

Where the provider's stable product ID exists inside the normalized event source.

product_id_path
Transaction identifier path

Stable sale/order identifier used for tracking and duplicate protection.

transaction_id_path
Customer fields

Email, name and other fields required for customer fulfillment.

customer_email_path
A provider contract should describe observable technical behavior — not marketing text about the provider.
Transport

Webhook, API, or Both?

ModelUse It WhenStrengthLimitation
Webhook onlyProvider pushes complete transaction data and offers sufficient authenticity controls.Fast event deliveryMay lack independent transaction lookup
Webhook + API verificationProvider pushes an event but offers a trusted API to confirm the order.Strong separation between notification and verificationRequires API credential and provider availability
API polling / lookupNo webhook exists or the workflow is manually triggered.Direct provider queryNot ideal for instant fulfillment
WordPress-native eventThe sale already happens inside WordPress.Direct application-level integrationSpecific to the local commerce source

Transport answers how data arrives. It does not automatically answer whether that data is trustworthy.

Authentication

How Evoxup Authenticates to the Provider

AuthenticationTypical ConfigurationWhere Used
Bearer TokenAuthorization: Bearer …API calls, discovery, transaction lookup
API Key HeaderX-API-Key: …Provider APIs using custom headers
Basic AuthenticationUsername + password/tokenLegacy or provider-specific APIs
Query CredentialKey included in query parametersOnly when required by provider design
No outbound authNoneWebhook-only providers without API access
Credentials should be stored as secrets and masked in the UI. A saved secret should not be rendered back into the browser simply to show that it exists.
Verification Policy

Do Not Force Every Provider Into HMAC

Verification must match the provider's real capability.

Verification MethodHow It WorksBest Fit
Signature / HMACCompute or validate a signature using the provider signing secret and raw payload.Providers with signed webhooks
Outbound API verificationUse the transaction ID from the event to retrieve the order directly from the provider.Providers with trusted order APIs
Authenticated callback tokenValidate a provider-specific token or secret included in the callback.Platforms with simple shared-secret callbacks
IP / network restrictionRestrict origin where the provider publishes stable network ranges.Supplementary control, not universally available
No native verificationUse the strongest feasible policy without pretending a signature exists.Legacy or limited providers
Important: “test” and “live” are transaction context. They are not substitutes for authenticity verification.
Normalization

Convert Every Provider Into One Internal Event Shape

Provider payloads differ. The Core should not care whether one provider says sale_id and another says order.data.id.

{ "provider": "custom_vendor", "transaction_id": "ORD-104992", "event_type": "sale.completed", "test_mode": false, "product_id": "prod_8731", "variant_id": "variant_pro", "customer": { "email": "customer@example.com", "name": "Customer Name" }, "amount": 4900, "currency": "USD", "verified": true }

Once the event is normalized, Product Mapping and fulfillment can operate without knowing the provider's original JSON structure.

Normalization is the boundary that prevents provider-specific field names from leaking into membership and licensing logic.
Product Discovery

Discovery Is Optional — but Valuable When the Provider Offers It

1
Test Connection

Confirm credentials and API accessibility.

2
List Products

Retrieve stable external IDs and provider metadata.

3
Store Discovery State

Present discovered items without creating mappings automatically.

4
Map Intentionally

Administrator assigns the correct internal destination.

If the provider does not offer a catalog API, manual mapping can still work as long as the external product identifier from transactions is stable.

Mapping & Sync

Custom Providers Can Participate in the Same Extensions

CapabilityWhat the Custom Provider Must SupplyWhat Evoxup Does
Product MappingStable external product IDRoutes the product to EVO Product / plan / supported target
Product SyncCatalog API and provider metadata fieldsRefreshes name, status, price, URL, variants where supported
Transaction fulfillmentVerified normalized sale eventRuns Core membership/licensing/entitlement pipeline
Duplicate protectionStable transaction identifierPrevents repeated fulfillment of the same sale
Testing

Test Events Should Exercise the Real Pipeline

A useful integration test should not bypass the exact steps that matter in production.

ReceiveTest event
VerifySame trust policy
MapReal route
FulfillControlled test outcome
RecordTraceable result
The test marker should exist for traceability and policy decisions. It should not silently disable verification or route through a completely different fulfillment engine.
Security

Secrets, Signatures and Boundaries

Mask Secrets

Show “Saved securely” rather than rendering raw credentials.

Replace Explicitly

Use a dedicated Replace Credential action to change saved secrets.

Verify Raw Payload

Signature schemes often require the exact raw body before parsing.

Separate Trust from Mapping

A known product ID does not prove the event is authentic.

Never use product matching, test mode, or the presence of a customer email as proof that an inbound webhook is legitimate.
Examples

Three Common Custom Provider Patterns

Pattern A — Signed Webhook ProviderWebhook

The provider sends the full sale payload and an HMAC signature.

POST /evoxup/webhook/custom-vendor X-Signature: 7f9a... 1. Read raw body 2. Validate HMAC 3. Parse JSON 4. Normalize transaction 5. Resolve product mapping 6. Fulfill 7. Store transaction result
Pattern B — Unsigned Webhook + API VerificationWebhook + API

The event itself is only a notification. Evoxup retrieves the order directly from the provider before fulfillment.

Webhook says: order_id = 104992 ↓ GET /api/orders/104992 Authorization: Bearer **** ↓ Provider API confirms: status = paid product_id = prod_8731 customer = customer@example.com ↓ Normalize → Map → Fulfill
Pattern C — No Product Discovery APIManual Mapping

The provider sends a stable product code in each transaction but does not expose a catalog endpoint.

transaction.product_code = "PRO-ANNUAL" Manual route: PRO-ANNUAL → EVO Product #42 → PRO membership policy

Product Mapping still works because routing only requires a stable external identifier.

Failure Handling

What Should Happen When Something Goes Wrong

FailureExpected ResultDo Not Do
Invalid signatureReject event and log verification failure.Do not map or fulfill.
API verification returns unpaidReject or hold according to policy.Do not create paid access.
Unknown external productRecord unmapped transaction / require mapping.Do not guess by product name.
Duplicate transaction IDIgnore repeated fulfillment.Do not issue a second membership/license.
API unavailableReturn retriable/verification failure state as appropriate.Do not silently treat failure as verified.
Credential missingBlock API-dependent operation and show clear configuration error.Do not expose internal secrets in the error.
FAQ

Custom Provider Questions

Does every provider need a ready-made Evoxup profile?

No. Ready-made profiles are guided shortcuts for known providers. Custom Provider exists so the architecture is not limited to that list.

Does every provider need a webhook signature?

No. Use the strongest verification mechanism the provider actually supports. Some providers are better verified through their API.

Can a Custom Provider use Product Mapping?

Yes, as long as transactions expose a stable external product identifier.

Can Product Sync work with a Custom Provider?

Yes when the provider exposes a suitable catalog API and the adapter defines how product metadata should be retrieved.

Can I create a provider using only marketing documentation?

No. A reliable integration needs the provider's actual webhook/API contract, authentication rules, payload fields and verification capabilities.

Should a Custom Provider create memberships directly?

No. It should normalize the verified commerce event and hand it to the same Core fulfillment pipeline used by other integrations.

Design Principle

A New Provider Should Add Translation — Not New Business Logic.

The integration knows the provider. Core knows the product, membership, licensing and entitlement rules. Keeping those responsibilities separate is what makes provider-neutral commerce maintainable.

Connect Your Provider

Webhook, API or Both — Bring the Provider Into the Same Evoxup Pipeline.

Define the technical contract once, then reuse Evoxup's product mapping, fulfillment, licensing and entitlement architecture.