Overview
A reward fulfillment integration orders something of value from a partner when a participant earns a reward. It adds a supply side to an outbound integration: a component type for the partner’s reward suppliers, a support campaign of one template per product, andREWARD webhooks scoped to those suppliers.
Examples use a generic partner named example. Integration Categories describes the model; this page is the build order.
When You Would Build One
Each product a client offers becomes a reward supplier, and templates live in their own
CONFIGURATION support campaign — Integration Categories explains why the model takes two campaigns.
The Finished Shape
example stands in for the partner. Name both campaigns after the partner and generation, as in Example V10 and Example V10 Support. Tab labels come from each view’s title, so renaming a view stops the build from diffing against the packaged one.
Before You Start
Install the maintained source when the duplicatable listing has one; the sequence below then becomes the checklist for confirming it against the partner page. Confirm the source’s type first — a pre-v10 type such asintegration-v1 is the partner’s legacy integration under the same name. Build the shape below when that is the only source available.
Making the partner installable for every client needs a registered, Extole-owned component — see Build a Packaged Integration with the Management API.
Three orderings are forced:
- The component type must exist before a template can carry it or the socket can filter on it.
- The support campaign and its templates must exist before the integration subscribes.
- The integration campaign must have been published once before it subscribes or attaches resources.
How to Build
Create the Supplier Component Type
Create a component type parented to the platform reward-supplier type:schema is required even when the type adds no rules of its own, and it is a JSON string rather than an object. Create the type before any template: an untyped template satisfies no socket filter, and typing it in place afterwards is unreliable.
Create the Integration and Its Sockets
Create theINTEGRATION campaign, root, and model component as described in Create the Integration Campaign and Component Model.
Declare the credential settings under the names the partner page uses — for BHN, merchantId (STRING) and clientKeyId (CLIENT_KEY). A prefixed invention such as bhnMerchantId is a distinct setting, and webhook client_key_id expressions plus request handlers that call context.getVariable("merchantId") will read null.
Then add the supplier socket, filtered to the type created above:
views socket whose filters accept every view type in use — the configuration type plus the report-runner and event-stream types.
Create the Support Campaign and Its Supplier Templates
Create aCONFIGURATION campaign with program type campaign-component, named for the integration it supports:
variables on a create — settings is the sub-path for adding one later — and every value sits under values.default, never a bare value.
Declare every setting the supplier below reads — dynamicValue, cashBackPercentage, cashBackMin, cashBackMax, financialAccountId — plus rewardSupplierId, which the platform reward-supplier type requires by name.
Name each template with the same token as its tag, so example-virtual carries internal:example-virtual; the Rewards page follows that match to offer the product. Give every template a rewardSupplierLogo, sourced as Set a Logo That Resolves describes.
Default enabled to false. The rewards list shows enabled suppliers only, so enabling a template is the marketer’s act.
Attach a Reward Supplier to Each Template
A reward supplier is created withcomponent_ids naming its template, the same way a webhook is.
type is the custom reward kind rather than the component type the template carries.
Four parts carry weight beyond their own value:
- The tag identifies the product variant: the order webhook’s supplier filter and the template’s supplier-identifier setting both resolve through it, so a mismatch is a supplier no webhook will fulfill.
- The display type names the product as a marketer sees it — “Example Virtual Cards” rather than the generic kind it falls back to when omitted. Variants of one product share one.
- The data map carries the identifiers the order request needs, because a request handler cannot read a setting on a component it does not own.
- The face-value algorithm resolves from the client’s toggle rather than being fixed in the template, with the percentage stored as a fraction.
$SUPPORT_CAMPAIGN_VERSION immediately before publishing.
This version-scoped publish is missing from the OpenAPI specification, so you will not find it in the API reference. That is a gap in the specification rather than a sign the operation is unavailable — this page and Validate and Publish an Integration are its documentation. The specification does carry
POST /v2/campaigns/{campaignId}/publish, the unversioned variant of the same action.REWARD_SUPPLIER_ID setting resolving its own element by that tag:
Subscribe the Integration to the Support Campaign
Subscribe the integration so its templates are installable; without it the socket accepts the right type and has nothing to offer:CLIENT_ID is this account’s own identifier, from GET /v2/me. The integration campaign must also have been published once.
Give the Reward Activity Tab Its Report and Feed
Build both views from Add the Activity and Event Views, which carries the view bodies, their elements, and the republish each attachment needs. Three values are reward-specific. The runner’smappings expression counts reward activity and the revenue behind it:
reportColumnsMapping names the columns it produces, describing this chart:
values.default serialized as an escaped JSON string:
$EVENT_STREAM_ID the create returned:
settingsToDisplay names the supplier socket. Copy its status expression rather than composing one; it reaches for the suppliers themselves instead of counting children, which breaks as soon as the tree gains a view:
Java.from before iterating it.
Create the Reward Webhooks
Create one webhook per partner order endpoint plus one status check, all typedREWARD and attached to the integration component through component_ids after a publish.
Create the webhook without filters — POST /v6/webhooks has no filters property:
POST /v4/webhooks/reward/{webhook_id}/filters/supplier:
POST /v4/webhooks/reward/{webhook_id}/filters/state:
supplier, state, tags, expression — and GET /v4/webhooks/reward/{webhook_id}/filters lists a webhook’s set. Reward states are a closed vocabulary: EARNED for order webhooks, FULFILL_FAILED for the status check.
Write the Request and Response Handlers
The request handler builds the partner order from the reward, the supplier’s data map, and the person’s profile. Where the partner page publishes that body — BHN does — write it asrequest with a matching response_handler, both properties of POST /v6/webhooks and PUT /v6/webhooks/{id}.
The handler runtime is:
Order webhooks commonly fulfill with
withSuccess(false) so the status check can close the reward later; always using withSuccess(true) reports rewards as delivered when the partner rejected them.
Leave the webhook disabled while a required credential or the payload contract is missing, then PUT the handlers and set enabled to true.
The Status-Check Webhook
The status-check webhook filters on every variant’s suppliers and onFULFILL_FAILED, on a schedule escalating from hours to days out to about a month. The order webhooks’ short schedule would exhaust a status check’s retries first.
Attach the Credential
Create the client key only once the partner’s secret exists — for certificate authentication, the certificate material rather than a placeholder — then set the credential setting. A missing credential does not block the build: leave it null and track it as outstanding.Error Handling
How to Test
Read the built campaign and its resources back:- The supplier socket filters to the partner’s type, whose parent is the platform reward-supplier type.
- The support campaign holds one correctly typed template per product the partner page names, each with a reward supplier attached, a variant tag, and its data map.
- Each webhook is type
REWARD, carries both filters, and resolves a non-empty supplier list. - Each webhook’s
requestandresponse_handlermatch the partner page — a default request builder does not — andenabledis true once the credential is set. - The webhook count matches the partner’s order endpoints plus one status check, not the number of products; several products ordered through one endpoint share a webhook.
- The account identifier is set and the credential is either configured or reported outstanding.
Validate and Publish an Integration covers the views, logos, and display settings.
