NewRich
Marketplace

License API

Implement redemption-code licensing so NewRich App Store can fulfill marketplace purchases.

License API

This page defines the redemption-code licensing API your app must expose so App Store can fulfill purchases. Implement these endpoints so customers receive access without NewRich storing pre-generated passwords.

API version: v1
Base path: /api/v1
Content type: application/json
Authentication: Caller domain allowlist + X-Licensing-Api-Key (see below)

Implement the request/response shapes, authentication rules, and idempotency behavior defined on this page. App Store sends both the license API key and caller-domain headers — your endpoints must validate both before processing the body.

Endpoints App Store calls

App Store stores the full versioned API root per product (for example https://dashboard.yourapp.com/api/v1) and appends resource paths:

App Store actionHTTP call
Purchase fulfilledPOST {license_api_url}/redemption_codes
Refund / cancel (contract; integrate when available)POST {license_api_url}/redemption_codes/revoke
Dispute resolved (contract; integrate when available)POST {license_api_url}/redemption_codes/reactivate

Authenticate App Store requests

Apply both checks below on all three licensing endpoints before processing the request body.

Private credentials. NewRich provides the license API key through a secure channel during marketplace onboarding. Store it in server configuration only — never in source control, client-side code, or public docs.

License API key

App Store sends a shared secret on every request. Your API must reject requests with a missing or incorrect key.

Request header: X-Licensing-Api-Key

Your configuration:

LICENSING_API_KEY=<provided privately by NewRich>

Compare the header value to your configured key using a constant-time comparison.

HTTPmsgWhen
401License API key required.Header absent or empty
403License API key is invalid.Header present but does not match
503Licensing API is not configured.LICENSING_API_KEY is not set

Caller domain allowlist

Your API must also reject requests that do not come from an authorized App Store hostname.

Your configuration:

LICENSING_ALLOWED_DOMAINS=apps.newrich.com

App Store production requests identify themselves with hostname apps.newrich.com.

Resolve the caller hostname

Read the caller in this order (first match wins):

  1. X-Licensing-Caller-Domain — preferred for server-to-server calls from App Store
  2. Origin — hostname extracted from the URL
  3. Referer — hostname extracted from the URL

Expect a hostname only (apps.newrich.com), not a full URL. Normalize case and strip ports when comparing.

Reject invalid callers

HTTPmsgWhen
401Caller domain required. Send X-Licensing-Caller-Domain, Origin, or Referer.No resolvable caller hostname
403Caller domain is not authorized.Hostname not in allowlist

Response envelope

Use the same JSON shape on all licensing endpoints.

Success:

{
  "success": true,
  "msg": "ok",
  "data": { }
}

Application error:

{
  "success": false,
  "msg": "Human-readable error message"
}

Validation error (HTTP 422):

{
  "message": "The email field is required.",
  "errors": {
    "email": ["The email field is required."]
  }
}

POST /redemption_codes — Generate

Issue an email-bound redemption code after purchase.

Request body

POST /api/v1/redemption_codes HTTP/1.1
Host: dashboard.yourapp.com
Content-Type: application/json
X-Licensing-Caller-Domain: apps.newrich.com
X-Licensing-Api-Key: <your-license-api-key>

{
  "email": "[email protected]",
  "order_id": "NR-42-17",
  "product_sku": "yourapp-pro"
}
{
  "email": "[email protected]",
  "order_id": "NR-42-17",
  "product_sku": "yourapp-pro"
}
FieldRequiredTypeNotes
emailyesstring (email)Must match at customer registration
order_idyesstringUnique per order line; idempotency key
product_skunostringOptional audit field; tier logic is yours
Field sourceNotes
emailBilling email from checkout (lowercased and trimmed)
order_idFormat NR-{order_id}-{order_item_id} — unique per line item

Minimum success response (HTTP 2xx):

{
  "success": true,
  "data": {
    "code": "YOUR-ABCD-EFGH-IJKL"
  }
}

App Store requires HTTP 2xx, "success": true (boolean), and a non-empty string data.code. A fuller response is fine:

{
  "success": true,
  "msg": "ok",
  "data": {
    "code": "YOUR-ABCD-EFGH-IJKL",
    "email": "[email protected]",
    "order_id": "NR-42-17",
    "status": "pending",
    "current_upgrade": "Pro"
  }
}

Behavior

  • Idempotent on order_id: duplicate generate calls return the same code (HTTP 200).
  • Revoked order: if the order was revoked, generate returns HTTP 409 with msg: "Order has been revoked."
  • Code format: your choice; reference apps use a prefixed alphanumeric format.
  • status: start as pending until the customer registers.
If your API errors or times out (default 15 seconds), the order still completes but the customer may not receive a redemption code. Monitor your endpoint and logs closely after launch.

POST /redemption_codes/revoke — Revoke

Disable a code or linked user account (refunds, chargebacks).

Request body — provide one of:

{ "order_id": "NR-42-17" }
{ "code": "YOUR-ABCD-EFGH-IJKL" }

code is case-insensitive.

Success (200) — same data shape as generate.

Code stateEffect
pendingStatus → revoked; registration blocked
redeemedLinked user disabled; code → revoked
already revokedIdempotent — return current state (200)
HTTPmsg
404Redemption code not found.

POST /redemption_codes/reactivate — Reactivate

Restore a previously revoked code or account.

Request body — same as revoke (order_id or code).

Prior stateEffect
Revoked, never redeemedStatus → pending (customer can register)
Revoked after redemptionUser re-enabled; code → redeemed
Not revokedIdempotent — return current state (200)
HTTPmsg
404Redemption code not found.

Redemption code lifecycle

stateDiagram-v2
    [*] --> pending: POST /redemption_codes
    pending --> redeemed: Customer registers
    pending --> revoked: POST .../revoke
    redeemed --> revoked: POST .../revoke
    revoked --> pending: POST .../reactivate (never redeemed)
    revoked --> redeemed: POST .../reactivate (was redeemed)
StatusMeaning
pendingIssued; awaiting one-time registration
redeemedCustomer created an account
revokedCancelled or disabled

Customer registration (your app)

Deliver the code from generate to the purchaser (App Store includes it in the order confirmation email). The customer completes registration at your public registration page.

Enforce at registration:

  • Code must exist and be pending
  • Email must match the email sent to generate (case-insensitive)
  • Code is one-time use
  • Revoked codes are rejected

This step is outside the license API. App Store never calls a validate or activate endpoint.

Implementation checklist

  • X-Licensing-Api-Key validation on all three routes (LICENSING_API_KEY, constant-time compare)
  • Caller domain allowlist on all three routes (LICENSING_ALLOWED_DOMAINS)
  • POST /api/v1/redemption_codes with email, order_id, optional product_sku
  • Unique order_id constraint and idempotent generate
  • HTTP 409 when re-generating a revoked order
  • POST .../revoke and POST .../reactivate accepting order_id or code
  • Disable linked user on revoke; re-enable on reactivate
  • Public registration page with email-bound, one-time code redemption
  • Share license API base URL and customer app URL with NewRich for listing setup

Before go-live

NewRich verifies your integration before your listing goes live — authentication, code generation, idempotency, registration, revoke/reactivate, and an end-to-end purchase. During marketplace onboarding, the team will share a private verification checklist and test steps for your endpoints. Do not publish license API keys or ad-hoc test commands in public documentation or support channels.

Copyright © 2026