Skip to content
Developer docs
⌘ K
Dashboard ↗

Releases

0.30.0

Added

  • GrizzleeTrackingClient creates a random device ID the first time it captures, keeps it in the storage you pass, under grizzlee-device:<publishable key>, and sends it with each capture. It sets no cookie. Grizzlee keeps only a keyed hash of it, with a keyed hash of the visitor's IP address, and compares them with the fraud rules when an order or claim uses the receipt. Without crypto.randomUUID or working storage, captures go without it.

Changed

  • updatePayoutSchedule saves a 30-day holdPeriodDays when you leave it out. It used to save 0. Terms you already saved keep their hold period. Send holdPeriodDays: 0 to keep paying rewards as soon as they are approved.

0.29.0

Read before upgrading

  • Partner summaries, the dashboard and the embed now hand out links in the short form ?ref=KARL7Q. They add program only when another of the partner's linkable programs uses the same page, and QR links add channel=qr. App and website builds on SDK 0.26.0 or older read only the grizzlee_ names, so they ignore these links. Before the Grizzlee release that publishes this version deploys, every app and site that captures referrals must ship a build on SDK 0.27.0 or newer. Links made earlier keep working in every version.

Changed

  • createReferralLink writes ?ref=<code>, plus program and channel only when given, and accepts a referral without programId. It first removes referral names already in the destination.
  • createPlayStoreUrl accepts a referral without programId and then writes ref and channel. With a program it keeps the grizzlee_ names, so older app builds still read it. extra skips ref, program, channel and every grizzlee_ name, even when the referral leaves them out.

0.28.0

Read before upgrading

  • Workspaces are now called companies everywhere in the API, SDK and webhooks. Nothing else about them changed. Rename these in your code:
    • getWorkspace() is getCompany(), and GET /api/v1/workspace is GET /api/v1/company. The snapshot type WorkspaceSnapshot is CompanySnapshot, and its tenant field is company.
    • Every tenantId field is companyId: on webhook events and every nested payload, and on rewards, partners, programs, payouts, attributions, orders, deliveries and the other records the API returns.
    • The error code workspace_limit is company_limit.
    • parseWebhookEvent now requires companyId and rejects an event body that has only tenantId. Process every webhook body you saved with an earlier version before you upgrade.
  • Receipts and checkout references issued before this release keep working.
  • createEmbedSession without locale used to mean English. It now uses the partner's language, then the company's default language. Pass locale: "en" to keep English.
  • A company has languages, and the first is its default. When it serves more than one, createProgram, and updateProgram with display, return 400 missing_translation unless each extra language has a publicName, and headline or milestoneLabel is set in every language or none. The message names the missing language.

Added

  • deleteProgram(id) calls DELETE /api/v1/programs/:id and returns ProgramDeletion, { id, result }. A program with no history is deleted with its versions, placement keys and enrollments. A program with referrals, rewards or other history is archived instead: paused, stripped of its placement keys and kept, with result: "archived".
  • Programs have an optional archivedAt. updateProgram and setPlacement reject an archived program with 409 program_archived.
  • Armenian ("hy") and Russian ("ru") join English and French ("fr-CA") wherever a locale is accepted or returned: partner locale, embed session locale, program display input, ProgramDisplay, terms.text and the embedded dashboard. EmbedLocale covers all four.
  • ProgramDisplay.milestoneLabel has few and many next to one and other, for languages such as Russian with more plural forms. Pick the form with Intl.PluralRules. Program input still takes one and other.
  • Rewards have optional explanationParts, order and milestone decisions reasonParts, and Stripe payouts lastErrorParts: the English explanation, reason and lastError as TextPart sentences, { code, params }, so you can show them in another language. The codes are RewardTextCode, DecisionTextCode and PayoutTextCode. The English fields are unchanged. Text saved before this release has no parts, and later releases can add codes, so fall back to the English text.
  • The company snapshot's company.languages lists the company's languages, default first.
  • The company snapshot's company may have delivery: { cash, credit }, the payout method a company picked for programs created from the dashboard. Saved programs keep their own delivery, and createProgram without delivery still uses "grizzlee_wallet" for both.

0.27.0

Read before upgrading

  • ReferralLink.programId is optional, since a link that carries only the partner's short code leaves it out. Code that reads it must handle undefined. createReferralLink and createPlayStoreUrl still require it.
  • Partner summary links, createReferralLink and createPlayStoreUrl still write grizzlee_ref, grizzlee_program and grizzlee_channel with the long code. A later release will switch generated links to the short form ?ref=KARL7Q, which SDK 0.26.0 and older ignore. Ship this version in every app and site that captures referrals before then.

Added

  • Partners have alias, a short code such as KARL7Q that is unique in the workspace and matches in any case. Captures, typed codes, checkout candidates and attributions accept it wherever they accept referralCode. Partner summary programs return it as alias.
  • readReferralLink, captureFromUrl, readBranchReferral, readAppsFlyerReferral and readInstallReferrer read ref, program and channel after the grizzlee_ names. A ref without a program counts only when it has the shape of a partner code, so ?ref=producthunt is ignored.
  • capture accepts a link without a program, with an optional destination page that picks the program. captureFromUrl sends the page for such links and returns null when ref names no partner.

0.26.0

Added

  • Programs accept an optional destinationUrl, the HTTPS page partner links and QR codes open. A published signup page's destination still takes precedence. updateProgram keeps an omitted destinationUrl, and null removes it. Changing it adds no program version.
  • createProgram accepts ProgramCreateInput, where currency is optional and defaults to the workspace currency. updateProgram keeps an omitted currency.
  • Programs accept optional display copy per language: publicName, headline and, for milestone programs, milestoneLabel with one and other. updateProgram keeps an omitted display, and null removes it. Changing it adds no program version. The input type is ProgramDisplayInput.
  • Capture, install claim, typed-code, incentive and placement responses include display: ProgramDisplay, the program's public name, headline and milestone label with fallbacks filled in. Typed-code and incentive answers return null when there is no program. resolvePlacement now returns the exported PlacementResolution type.

0.25.0

Added

  • Partner creation, upserts and updates accept addProgramIds and removeProgramIds. These change individual enrollments and preserve the rest.
  • Enrollment writes reject a program on both sides with 422 conflicting_programs. Do not combine additions or removals with programIds, which still replaces the whole list.

0.24.0

Added

  • Workspace placements map stable keys to programs. The server client lists and reads them, points a key at a program with setPlacement, and removes one with deletePlacement.
  • Embed sessions accept a placement key, enroll a partner in its active program when needed, and return the saved placement key.
  • The tracking client resolves placements with a publishable key. Capture, install claim redemption, typed code and referral claim responses include the current placement keys for the captured program.

0.23.0

Added

  • Optional layout: "full" | "simple" on createEmbedSession. Sessions return the layout, which defaults to "full". The simple layout shows an offer, referral link, progress and Share, with lists behind a detail link.

0.22.0

Added

  • Offer programs use rewardType: "offer" and partnerOffer. Each qualifying referred order earns a discount with frozen terms and expiry. Offers use the existing review, approval, rejection and reward webhooks. They have zero money amounts and no ledger entries, wallets or payouts.
  • Checkout responses add incentiveKind and earned offers include rewardId. Holds and uses keep those fields. The existing incentive endpoints redeem earned offers through a partner's linked customer IDs. An eligible friend offer wins; earned offers use the soonest expiry first.
  • Partner reward reads add offer with status, terms, remaining uses, recorded uses, open holds and expiry, and accept a rewardType filter. Embed rewards add rewardType and localized offer details.
  • Export PartnerOffer, PartnerOfferInput, EarnedOfferTerms, OfferTerms, IncentiveKind and EarnedOfferStatus.

Changed

  • Incentive response terms now use the OfferTerms union. IncentiveIneligibleReason adds offer_voided. Reward and program rewardType can be "offer". Update exhaustive switches for these unions.
  • Upgrade the SDK before enabling an offer program. Older parseWebhookEvent rejects rewardType: "offer" in reward webhooks.

0.21.0

Added

  • payout.reversed and PayoutReversedWebhookPayload report cash returned by a Stripe transfer reversal, including partial reversals. The payload includes reversalCents, the new amount returned, reversedCents, the cumulative total, reversedAt and partial.
  • Payouts can have status reversed, with reversedCents and reversedAt. Merchant delivery history appends RewardDelivery records with status reversed and reversalOfId. Original deliveries and earned rewards stay intact.
  • Optional customerDisplayName on attribution creation, referral claims, code attachments and completed orders. Names accept 1 to 80 characters after trimming. Each referral keeps its latest accepted name. Customer erasure clears names and prevents later writes from restoring them.
  • Export EmbedReferral, EmbedReferralPage, EmbedReward and EmbedRewardPage for partner-facing responses.
  • orderCount on PartnerSummaryProgram, returned by getPartnerSummary and embed summaries. It totals each referral's distinct rewarded orders across the whole program without pagination. Renewals do not add orders. Reversed rewards still count; milestone rewards and orders that earned nothing do not.

Changed

  • Stripe transfer reversals restore payable merchant cash or available wallet cash once, even when events repeat or arrive out of order. Subscribe to transfer.reversed on the merchant Stripe connection and select payout.reversed on your Grizzlee webhook endpoint.
  • Partner balances, scheduled payouts and the dashboard account for returned transfers. Embed payouts expose reversedCents, or null when a mixed-program payout extends beyond the embed scope.
  • Embedded referral and reward responses omit merchant customer and order IDs and use opaque row keys. Referrals show the display name or a neutral label in the session language. Merchant API responses retain real IDs.
  • Stripe metadata and Shopify order note attributes can supply grizzlee_customer_display_name. Provider billing names are not shared automatically.

0.20.0

Added

  • deliverPartnerCredit(externalId, input) records one merchant credit entry across approved credit rewards, oldest approval first. recoverPartnerDebts(externalId, input) settles delivery debts of one currency and reward type, oldest debt first. Both use rewards:deliver, return their allocations and replay the original result for the same reference. Existing per-reward calls remain available.
  • version on PartnerMerchantBalance. Cash, credit and program merchant balances share one partner-wide accounting history count, computed when read. Existing history contributes to the initial version. Re-read the summary after reward webhooks and ignore older versions. No new webhook type is required.
  • Exported types PartnerCreditDeliveryInput, PartnerCreditDeliveryResult, PartnerDebtRecoveryInput and PartnerDebtRecoveryResult, plus the SDK input and response aliases for both calls.
  • Optional programIds on createEmbedSession limits every embed read to those partner memberships. Sessions return the selected IDs, or null for all programs. Scoped summaries omit partner-wide wallet balances and payout wait dates. Scoped payouts show selected merchant allocations, with a null net amount when mixed-program debt cannot be split.
  • milestone, milestoneCount and milestoneThreshold on milestone partner referrals, including progress before earning. Partner rewards expose their saved count and threshold. Export EmbedSummary, EmbedPayout and EmbedPayoutPage.
  • Embed hosts can opt in to grizzlee:share with program ID, referral URL and localized invitation text. The embed shows milestone progress in English and French Canadian.
  • Milestone programs can pay on each report, as a fixed amount or a percentage of optional valueCents, with an optional report limit. They can also pay a fixed bonus at a count. Exported MilestoneRewards; each-report rewards carry reportEventId and the reported value. Reversing a report takes back its reward and rechecks the bonus.
  • Partner promo code methods listPartnerPromoCodes, createPartnerPromoCode, renamePartnerPromoCode and deactivatePartnerPromoCode, with types ProviderPromoCode, ProviderPromoCodeInput and RenameProviderPromoCodeInput. Stripe and Shopify orders attribute applied partner discounts through code candidates.
  • Per-program tracking switches for links, QR codes, typed attribution codes and provider promo codes, with the TrackingMethods type. Partner summary programs expose tracking, attributionCode, promoCodes and qrLink. Provider code candidates and selection winners carry providerPromoCodeId.
  • Exported types ReferralCandidate, ReferralSelection, ReferralSkipReason, ClaimReferralInput and ClaimReferralResult. Order webhooks include referralSelection when checkout supplied candidates.
  • Optional newCustomer on ReferralIncentiveInput, ReserveIncentiveInput and OrderEvent. Your server supplies newness from its own history, including placed but unpaid orders. Send it on referred purchases and skip unrelated orders and past order-count imports.
  • Reservations, orders and order.completed webhook payloads keep the supplied answer. Reservation and order replays reject a changed answer with their existing conflict errors. Reservation replays can omit the answer to keep the saved value.
  • When an order supplies newCustomer, first_order and first_n_orders count purchases after the referral. Returning customers can earn partner rewards. newCustomer: false blocks only friend offers with newCustomersOnly: true. Omitting the field preserves the workspace-count fallback.

Changed

  • Reports for erased customer IDs remain accepted and keep normal referral, reward and refund behavior. Grizzlee discards identity signals, customer emails and personal reasons. Partner erasure removes the partner's personal data and customer ID links, and suppresses its identity signals from later reports. Linked customer records stay. Queued Stripe and Shopify reports for erased customers clear their raw bodies and mappings when processing finishes, so merchants no longer need a second erasure after late reports.

  • Breaking: milestone programs use milestoneRewards.eachReport and milestoneRewards.atCount. The milestone trigger no longer takes count. Omit order-only compensation and duration; custom milestone terms use milestoneRewards too. Existing stored programs and reward snapshots retain their original fixed bonus and count through migration.

  • Program kind no longer restricts tracking methods. New programs enable links, QR codes and typed codes by default. Existing affiliate programs migrate with typed codes off. Provider promo codes start off and require a connected provider. Provider discounts keep their original friend incentive after program edits.

  • Breaking: checkout inputs on getReferralIncentive, reserveIncentive, claimReferral and completeOrder use candidates instead of one receipt, referralCode or referralReceipt. The newest valid receipt or typed code wins while attribution is open, or for an order-only program. Qualified customer attributions keep their partner. Skipped candidates report customer_already_referred. Invalid candidates are skipped, and checkout continues when none wins. referralSelection reports the winner and a reason for every skipped index. claimReferral returns { attribution, referralSelection }. Empty or invalid-only lists without a retained qualified attribution return no referral, with null program, partner and terms in incentive responses. Omit candidates to use recorded referrals. Holds and completed orders keep their selection on retries.

  • Breaking: reserveIncentive requires orderId instead of checkoutId. Call getReferralIncentive at quote time and reserve only when the order is placed. Holds last until completion or release, with no timer or maximum duration. Completion can find the hold by order ID.

  • Remove lockIncentive, LockIncentiveInput, IncentiveReservationLock, maxIncentiveLockDays, reservationMinutes, reservation expiresAt and the expired reservation status. Historical expiry flags on completed orders remain readable.

  • listIncentiveReservations takes an optional object with customerId and olderThanDays. The age filter lists open holds only. A competing hold returns eligible: false with reason reservation_open instead of throwing 409. Reserve replays reject a changed supplied newCustomer with order_conflict and keep the saved value when omitted.

  • Breaking: partners use optional customerIds to link their own merchant customer accounts. externalId no longer identifies self-referral or supplies customer identity signals. Supplied lists replace the links, and [] clears them. Partner erasure removes the links.

  • Replace selfReferralCheck and SelfReferralCheck with fraudChecks.selfReferral.action, using block, review, flag or off. The default is block, and off disables customer-link checks too. Orders, checkout checks, direct attribution and milestones use the same action policy.

  • Self-referral responses and webhooks accept customer_id in signals. Export SelfReferralSignalType. Update webhook consumers before using customer links. Existing partners gain no implicit links, and earned rewards and saved rules stay intact.

  • Breaking: orders require commissionableCents, the merchant-selected amount percentage rewards use. Optional totalCents reports what the customer paid. These replace order amountCents and subtotalCents.

  • Remove program commissionBase and the CommissionBase type. Every new percentage reward uses the commissionable amount. Earned rewards and their saved rules stay intact. Historical subtotal rewards carry Reward.historicalBasis: "total" for later refunds and adjustments.

  • Refunds use refundedCommissionableCents and optional refundedTotalCents. Fixed rewards prorate on the commissionable ratio. Only explicit fullRefund: true marks an order fully refunded.

  • Order adjustments use commissionableCents, totalCents, adjustedCommissionableCents, adjustedTotalCents, previousCommissionableCents and previousTotalCents. Reporting totals never change new rewards.

  • Stripe charge metadata uses grizzlee_commissionable_cents and optional grizzlee_total_cents, with matching cumulative refund keys. Shopify and Stripe invoice reporting totals now include the customer's full payment.

0.19.0

Added

  • duration: { type: "months", months } on programs, from 1 to 1,200 months. Orders earn until the same calendar date that many months after the customer's first rewarded order in the program, in UTC, so 12 months pays 12 monthly subscription invoices. ReferralReceipt.duration and the capture response's duration can be "months".
  • checkoutReference on CaptureReferralResponse and on ReferralReceipt: a short signed reference to the capture that fits a Stripe Checkout Session's client_reference_id. Capture and redeemInstallClaim return it, and the tracking client stores it with the receipt. Receipts stored before this version leave it out.
  • adjustOrder(input) and the order.adjusted event on sendEvent: set a completed order's new amountCents, subtotalCents or both, with an optional reason. Rewards are recalculated under the rules they were earned with. The OrderAdjustmentEvent and OrderAdjustment types.
  • adjustedCents?: number on Reward, the signed total of order adjustments. A reward is worth originalCents + (adjustedCents ?? 0) - reversedCents. adjustedCents on PartnerReward and on reward webhook payloads.
  • adjustedSubtotalCents, adjustedAmountCents, lastAdjustedAt and adjustments on Order, increasedCents on EventResult, and the adjustment ledger entry kind.
  • The order.adjusted and reward.adjusted webhooks, with the OrderAdjustedWebhookPayload and RewardAdjustedWebhookPayload types.

Changed

  • Program terms text describes months durations in English and Canadian French, such as "20% of each order your friend places in their first 12 months".
  • Refunds after an order adjustment measure against the adjusted totals. amountCents on reward webhooks and partner reads includes adjustments.
  • Upgrade the SDK on every webhook endpoint before you subscribe to order.adjusted or reward.adjusted. Older versions throw on these types.

0.18.0

Added

  • Counted milestones. A milestone trigger takes an optional count, from 1 to 10,000: { type: "milestone", milestone: "task_completed", count: 10 }. Report each occurrence with reportMilestone under a new eventId, and the program pays once the person's reports since their referral reach count. Without count, or with 1, the first report pays, as before. Merchants change count in the dashboard without a code change. A change creates a new program version, and earned rewards keep the count they were earned under.
  • reverseMilestoneReport(input), for POST /api/v1/milestones/reverse, takes back one report, for example a job cancelled after it was reported. Type ReverseMilestoneReportInput, { eventId, reportEventId, reason? }. A reward whose count falls below its threshold is reversed with a reversal ledger entry and reward.reversed, and a delivered merchant reward becomes partner delivery debt, as after a refund. A later report that brings the count back restores it with reward.restored.
  • The milestone.reversed webhook, with reportEventId, reversalCents, reversedAt and an optional reason. Type MilestoneReversedWebhookPayload.
  • count on MilestoneResult and on every milestone webhook: the person's reports of the milestone that are not reversed. reportEventId on MilestoneResult for reversals.
  • milestoneCount and milestoneThreshold on milestone Decisions, milestoneCount and milestoneRevoked on milestone Rewards, and restoredCents on report results and milestone.reported.
  • MilestoneStatus gains reversed, and LedgerEntry.kind gains reversal.
  • missingStripeAccount?: "manual" | "wait" on PayoutScheduleInput and PayoutSchedule. "wait" creates no scheduled payout for a partner without a stripeAccountId. Its rewards roll over and the first due date after it gets an account pays them by Stripe transfer. "manual", the default, keeps today's manual payout. "wait" needs stripeIntegrationId.
  • The payout.account_required webhook and the PayoutAccountRequiredWebhookPayload type. A scheduled run sends it once per wait, when it first holds a partner's payout for a missing Stripe account. It also sends the partner's payout details needed email.
  • payoutAccountRequired, awaitingPayoutAccount and awaitingPayoutAccountSince on PartnerSummary.

Changed

  • updatePayoutSchedule replaces every term, so a call without missingStripeAccount saves "manual". Send it on every save once you use "wait".
  • A report while the milestone is revoked now counts toward the person's count. It still earns nothing until a reinstatement.
  • A reinstatement leaves a reward reversed when its count is below its threshold. It comes back when reports bring the count back.
  • parseWebhookEvent accepts unknown fields in a reward's programSnapshot.trigger. Older SDK versions reject reward webhooks from a program with a count, so update before you set one. They also throw on milestone.reversed, which new webhook endpoints do not subscribe to unless you add it.

Documentation

  • Public merchant help center with dashboard instructions for setup, partner invitations, rewards, payouts, refunds and troubleshooting.

0.17.0

Added

  • Per-program earnedCents, reversedCents, referrals, payouts and balances in PartnerSummaryProgram. Merchant balances keep the partner-wide shape. Program wallet balances expose pending and approved rewards only, because wallet operations have no program allocations. Paid merchant payouts contribute each program's gross reward allocations.
  • Optional expectedProgramId on claimReferral. A receipt from another program fails before mutation with 409 program_mismatch and details: { expectedProgramId, programId }.
  • locale on PartnerInput, PartnerUpsertInput, PartnerUpdateInput and Partner: the language of the partner's emails, "en" or "fr-CA". Without it, partner emails use the workspace's default language. null removes it.
  • partnerEmails on ErasureCounts: partner email log rows whose address a partner erasure removed, plus queued emails it skipped.
  • categories?: string[] on OrderEvent, for completeOrder, sendEvent and simulate, and on ReferralIncentiveInput, ReserveIncentiveInput and LockIncentiveInput. Slugs of 1 to 40 letters, digits, hyphens or underscores, up to MAX_ORDER_CATEGORIES (20). Grizzlee lowercases, deduplicates and sorts them.
  • orderCategories?: OrderCategoryRules on ProgramInput, Program and FriendIncentive, with include and exclude lists of up to MAX_CATEGORY_RULES (50) slugs. The program's rules decide rewards. The friend incentive's rules decide the discount. ProgramUpdateInput keeps omitted rules and removes them with null.
  • The category_not_eligible reason on IncentiveIneligibleReason and IncentiveFlagReason.
  • categories?: string[] on IncentiveReservation, the categories sent when it was made.
  • orderCategoryMismatch(rules, categories), which trims and lowercases both sides before comparing, normalizeOrderCategory(value), the MAX_ORDER_CATEGORIES and MAX_CATEGORY_RULES constants, and the OrderCategoryRules and OrderCategoryRulesInput types.

Changed

  • Partner summaries keep programs with past rewards, referrals, payout allocations or debt after the partner leaves. Each program has member to distinguish current and former memberships. Former programs return no referral link or friend incentive, and both dashboards label them as former programs.
  • partner.created payloads carry locale when the partner has one. Older SDK versions keep extra partner fields, so they still parse these payloads.
  • An order whose categories fail a program's orderCategories is skipped in that program. It still counts as a purchase, so it takes a purchase number and counts against first-order rules and new-customer offers.
  • parseWebhookEvent is more forgiving from this version on. It accepts incentiveFlag.reason values it does not know, extra fields in a reward's programSnapshot.friendIncentive and programSnapshot.orderCategories, and any strings in order.completed categories, so later additions to these do not break it.
  • Upgrade the SDK on every webhook endpoint before you set orderCategories on a friend incentive. Older SDK versions throw on order.completed, incentive.flagged and reward events that carry category_not_eligible or a friend incentive with orderCategories. A program's own orderCategories and an order's categories still parse in older versions.
  • An empty categories list on getReferralIncentive, reserveIncentive or lockIncentive means the checkout has no categories. Leaving the field out on a reservation replay or lock checks the categories the hold was made with. On an order event an empty list is stored as no categories.

Documentation

  • Public developer docs with a first-referral and first-order walkthrough, HTTP and SDK references generated from the code, searchable guides, and a validated example for every webhook event.

0.16.0

Added

  • fraudChecks on ProgramInput and Program: per-program fraud rules beyond self-referral. duplicate_accounts (customers a partner referred share a card or device), rapid_repeats (several referrals within minutes from one device), repeat_customer (the customer shares a phone, card or device with another customer already rewarded in the program) and disposable_email. Each rule takes action block, review, flag (the default) or off, and the velocity rules take thresholds from 2 to FRAUD_THRESHOLD_MAX (200) and windows. IP addresses are left out unless ipAccounts or ipReferrals is set.
  • fraud?: FraudMatch on Reward, Decision, ReferralIncentive and IncentiveReservationResult.
  • The fraud incentive ineligibility reason, returned by getReferralIncentive, reserveIncentive and lockIncentive when a blocking rule fires.
  • The fraud.flagged webhook and the FraudFlaggedWebhookPayload type.
  • Types FraudChecks, FraudChecksInput, FraudMatch, FraudRuleAction, FraudRuleId and FraudRuleMatch, and the fraudRuleIds and FRAUD_THRESHOLD_MAX constants.
  • rewardStatus: "review" on getWorkspace, and report.heldRewards on WorkspaceSnapshot.

Changed

  • Every program now runs the fraud rules with their defaults. Each rule defaults to flag: the reward follows the usual approval, records fraud and sends fraud.flagged. Nothing is held or blocked until you set a rule to review or block. Rewards held for review are skipped by automatic approval. Approve them with approveReward or reject them with rejectReward.
  • parseWebhookEvent accepts fraud.flagged and rewards with fraud. Older SDK versions throw on the new type, so update before you add it to an endpoint. Reward webhooks with fraud still parse in older versions.

0.15.0

Added

  • Install claims carry a web capture into a freshly installed app without fingerprinting. capture({ ..., installClaim: true }) returns installClaim: { code, expiresAt }, and redeemInstallClaim(code) exchanges the code for the visit's receipt through POST /api/tracking/:publishableKey/install-claims/redeem. A code works once and for at most 7 days. Unknown, used or expired codes throw 404 install_claim_unavailable.
  • captureInstallReferrer(referrer) handles the Android Play Install Referrer at first launch. It redeems grizzlee_claim or captures grizzlee_ref and grizzlee_program, and remembers the referrer so later launches do nothing. It never replaces a receipt already stored for the same program, because the referrer's visit came before the install.
  • createPlayStoreUrl({ packageName, installClaim?, referral?, extra? }) builds a Play Store link with that referrer. readInstallReferrer(referrer) reads one.
  • readBranchReferral(payload) and readAppsFlyerReferral(payload, { keys }) read a referral from Branch and AppsFlyer deep link payloads, including deferred deep links after install, and return the same shape as readReferralLink.
  • isInstallClaimCode(value), normalizeInstallClaimCode(value), INSTALL_CLAIM_PARAM and the types InstallClaim, InstallReferrer and AppsFlyerReferralKeys. CaptureReferralResponse has an optional installClaim.

Changed

  • @grizzlee/sdk/tracking also exports readReferralLink, so a landing page needs one import.
  • readReferralLink and captureFromUrl read the query by hand when URLSearchParams.get is missing, as in React Native. Values are trimmed, and values longer than 120 characters are ignored, matching what capture accepts.

0.14.0

Added

  • reinstateMilestone(input), for POST /api/v1/milestones/reinstate. It undoes a revocation: every reward the revocation reversed is restored with a restoration ledger entry and reward.restored, a delivered reward reduces the partner's delivery debt, and the milestone can earn again. Type ReinstateMilestoneInput, { eventId, customerId, milestone, reason? }.
  • restoredCents on MilestoneResult, set on reinstatements.
  • The milestone.reinstated webhook, with restoredCents, reinstatedAt and an optional reason. Type MilestoneReinstatedWebhookPayload.

Changed

  • MilestoneStatus adds "reinstated", which reinstatements return.
  • A revocation is no longer permanent. A revoked milestone earns nothing until it is reinstated, and it can be revoked again after that. milestone.revoked fires for each revocation that revokes the milestone, so one person and milestone can send it more than once. Use a new event ID for every revocation and reinstatement.
  • parseWebhookEvent accepts milestone.reinstated. Older SDK versions throw on it, so update before you add it to an endpoint.

0.13.0

Added

  • erasePartner(partner) and eraseCustomer(customerId), for POST /api/v1/partners/:id/erase, POST /api/v1/partners/by-external-id/:externalId/erase and POST /api/v1/customers/:customerId/erase. They erase a person's personal data and keep amounts, dates, statuses, IDs and the ledger.
  • Types PartnerErasureResult, CustomerErasureResult and ErasureCounts, and constants ERASED_PARTNER_NAME and ERASED_TEXT.
  • erasedAt on Partner.
  • The partner.erased and customer.erased webhooks. Types PartnerErasedWebhookPayload and CustomerErasedWebhookPayload.

Changed

  • parseWebhookEvent accepts the two erasure event types, and a partner.created payload with an empty email, which a partner erased before delivery has. Older SDK versions throw on the new types, so update before you add them to an endpoint.
  • Registering, upserting or updating an erased partner throws 409 partner_erased.
  • A failRewardDelivery retry with an externalReference already recorded matches any reason once erasure replaced the stored reason.

0.12.0

Added

  • stripeAccountId on Partner, PartnerInput, UpsertPartnerInput and the partner update inputs: the partner's Stripe connected account (acct_...). Setting it needs a key with payouts:write as well as partners:write. null removes it.
  • stripeIntegrationId on PayoutScheduleInput and PayoutSchedule. When set, scheduled payouts to partners with a stripeAccountId are sent as Stripe transfers from your Stripe balance, and end with payout.paid or payout.failed. Defaults to null, which keeps every scheduled payout manual.
  • cancelPayout(payoutId, { confirmNoTransfer: true }) releases a Stripe payout held in needs_action after you checked Stripe and found no transfer. It works only 24 hours after the last transfer request, when no worker holds the payout, and after Grizzlee's own complete search of Stripe finds nothing. Otherwise it throws 409 transfer_recent or transfer_found. Type CancelPayoutRequest.
  • transferGroup on Payout and payout webhooks: the Stripe transfer_group Grizzlee sets on a transfer, grizzlee_payout_<payout ID>.
  • provider, integrationId and destination on merchant payouts in createPartnerPayout. With provider: "stripe", Grizzlee sends the net amount through the named Stripe connection.

Changed

  • recoverPartnerDebt, deliverReward with nettedDebtCents and new merchant payouts with nettedDebtCents throw 409 debt_in_payout when they would settle cash debt that an open merchant payout already nets.

  • destination is optional on Stripe payouts in createPartnerPayout, wallet or merchant. It defaults to the partner's stripeAccountId.

  • Payouts can now combine mode: "merchant" with provider: "stripe". A payout.created handler should send money only when provider is "manual".

  • getPartnerByExternalId, upsertPartner, updatePartner and updatePartnerByExternalId leave out stripeAccountId for keys without payouts:write.

  • Once Grizzlee has sent a Stripe transfer request, it never fails or cancels the payout on its own. A refusal, including insufficient funds, now holds the payout in needs_action with the reason in lastError. Before, a wallet payout refused for insufficient funds on its first attempt failed and released its reservation. Look in Stripe for transfer group grizzlee_payout_<payout ID>, then call markPayoutPaid with the tr_ ID or cancelPayout with confirmNoTransfer.

  • PUT /payout-schedule still replaces all the terms. Saving terms without stripeIntegrationId turns Stripe payouts off.

0.11.0

Added

  • lockIncentive(reservationId, { orderId, expiresAt?, signals? }) for POST /api/v1/referrals/incentive/reservations/:id/lock. It locks an open friend-incentive hold to the order placed with it, so the hold lasts until that order completes or you release it, up to 180 days after the first lock. Only that order's completion consumes it, and the completion can leave out reservationId.
  • lock on ReserveIncentiveInput, to reserve and lock in one call.
  • lock?: IncentiveReservationLock (orderId, lockedAt) on IncentiveReservation and IncentiveReservationResult.
  • maxIncentiveLockDays, the 180-day limit.
  • Types LockIncentiveInput and IncentiveReservationLock.
  • The reservation_locked incentive flag reason, for an order that sends a hold locked to another order.

Changed

  • IncentiveFlagReason and the webhook schemas accept reservation_locked. parseWebhookEvent in older SDK versions throws on an incentive.flagged, order.completed or reward webhook that carries it, so update before you lock holds.

0.10.0

Added

  • clicks.total and clicks.last30Days on PartnerSummary and each PartnerSummaryProgram, returned by getPartnerSummary. Counts include recorded link and qr activity, including code attachments marked with either channel. coupon and in_app records are excluded. Repeat visits count separately.
  • Type PartnerClickCounts.

0.9.0

Added

  • version and updatedAt on Program. A new program is version 1, and every saved change except a rename adds 1.
  • programVersion on Reward, IncentiveReservation, IncentiveReservationResult, PartnerReward and every reward.* webhook payload. It names the program version the reward or reservation was made under. Older rewards and reservations have none, and PartnerReward.programVersion is null for them.
  • listProgramVersions(programId) and getProgramVersion(programId, version), for GET /api/v1/programs/:id/versions and GET /api/v1/programs/:id/versions/:version.
  • Types ProgramVersion, ProgramVersionDetail and ProgramVersionList.

Changed

  • webhookPayloadSchemas accept programVersion on reward payloads and on the nested reward.
  • updateProgram rejects version and updatedAt, as it already rejects id, tenantId and createdAt. Remove them when you send a fetched program back.

0.8.0

Added

  • The milestone.reported webhook, sent for each new milestone report, rewarded or not. Type MilestoneReportedWebhookPayload.
  • The milestone.revoked webhook, sent the first time a milestone is revoked for a person. Type MilestoneRevokedWebhookPayload.
  • Type MilestoneWebhookFields, the fields both milestone webhooks share.

Changed

  • parseWebhookEvent accepts the two milestone event types. Older SDK versions throw on them, so update before you add them to an endpoint.

0.7.0

Added

  • The reward.debt_recorded webhook, sent when a refund, a milestone revocation or a refund before a payout was paid leaves a partner owing part of a delivered reward. Type RewardDebtRecordedWebhookPayload.
  • The reward.debt_settled webhook, sent once for each recovery, netting or restoration of that debt. Type RewardDebtSettledWebhookPayload.
  • The referral.displaced webhook, sent when another partner's referral takes a customer over. Type ReferralDisplacedWebhookPayload.
  • incentiveAppliedCents and incentiveFlag on reward webhooks for orders that reported a friend discount.
  • IncentiveFlaggedWebhookPayload and SelfReferralDetectedWebhookPayload are now exported from the server import too, as the webhook import already did.

Changed

  • parseWebhookEvent accepts the three new event types. Older SDK versions throw on them, so update before you add them to an endpoint.

0.6.0

Added

  • signals on attachReferralCode, getReferralIncentive, reserveIncentive, completeOrder, upsertPartner, registerPartner, updatePartner and updatePartnerByExternalId. Grizzlee keeps keyed hashes of the email, phone, card fingerprint, device ID and IP address and uses them to catch self-referrals.
  • selfReferral on referral incentive lookups, reservations, code attachments, order decisions and rewards. It names the matching signal types and whether Grizzlee blocked the referral, held the reward for review or only flagged an IP match.
  • selfReferralCheck on programs: block, review or off.
  • rejectReward to reject a pending reward, including one held for a self-referral review.
  • The self_referral.detected webhook and the SelfReferralDetectedWebhookPayload type.
  • Types IdentitySignals, IdentitySignalType, SelfReferralAction, SelfReferralCheck, SelfReferralMatch and RejectRewardInput.

Changed

  • getReferralIncentive and reserveIncentive return eligible: false with reason self_referral when a program blocks a match. attachReferralCode throws self_referral with details.signals.
  • A customer whose customerEmail matches the partner's email follows the program's selfReferralCheck. Programs without the setting still block it.

0.5.0

Added

  • getPayoutSchedule and updatePayoutSchedule to set workspace payout terms: weekly or monthly due dates, a minimum payout and a hold period. Grizzlee creates merchant payouts on each due date and sends payout.created.
  • schedule on payouts and payout webhooks, with dueOn and approvedBefore, on payouts the schedule created.
  • Types PayoutSchedule, PayoutScheduleInput, PayoutScheduleRun, PayoutWeekday, GetPayoutScheduleResponse, UpdatePayoutScheduleInput and UpdatePayoutScheduleResponse.

0.4.0

Added

  • First public npm release, with ESM and CommonJS entry points and matching TypeScript declarations.
  • reserveIncentive, releaseIncentive and listIncentiveReservations to hold friend offers during checkout.
  • importCustomers to record existing customers' prior order counts.
  • reportMilestone and revokeMilestone to reward and reverse referral milestones.
  • Types for milestone triggers, readable reward terms and reward webhook sources.
  • FixedRefundMode to choose whether fixed rewards survive partial refunds.

Changed

  • completeOrder accepts reservationId and returns customer order counts and incentive flags. Report every completed order, including orders without referrals.
  • getReferralIncentive is a preview. Use reserveIncentive to price a checkout.
  • updateProgram keeps omitted fixedRefundMode unchanged.

0.3.0 and earlier

Earlier versions were shipped as tarballs and are not on npm.