GraphQL API
How to use the Stigg API on the server-side
The GraphQL endpoint
The GraphQL API has a single endpoint:
https://api.stigg.io/graphql
The endpoint remains constant no matter what operation you perform.
Retrieving the server API Key
In the Stigg Cloud Console, go to Settings > Account > Environments.
Copy the Server API key of the relevant environment.
Discovering the GraphQL API
GraphQL explorer
You can run queries on real Stigg data using our GraphQL Explorer, an integrated development environment in your browser that includes docs, syntax highlighting, and validation errors.
To authenticate you need to pass the Server API key in the X-API-KEY request header.
GraphQL introspection
GraphQL is introspective. This means you can query a GraphQL schema for details about itself.
You can run an introspection query by passing your Server API key as a query parameter:
https://api.stigg.io/graphql?apiKey=YOUR_SERVER_API_KEY
For example, running the following curl, will get all the available root types:
curl --request POST
--header 'content-type: application/json'
--url "https://api.stigg.io/graphql?apiKey={YOUR_SERVER_API_KEY}"
--data '{"query":"query { \_\_schema { types { name } } }"}'
Provisioning customers
When a new customer is provisioned within your application (for example: as part of your registration or onboarding process), you should also provision them in Stigg.
The customer's billing information can also be passed to Stigg when a customer is created or updated. When Stigg is integrated with additional service, this information will be propagated to the active integrations. The billing information is not persisted on Stigg's servers.
You can optionally pass subscriptionParams
to create subscription for that customer using a single operation. Doing so, will allow Stigg admins to override the requested subscription with no-code from the Stigg Console using the product's Customer Journey configuration.
Query
mutation ProvisionCustomer($input: ProvisionCustomerInput!) {
provisionCustomer(input: $input) {
customer {
refId
name # optional
email # optional - billing email address
createdAt
billingId
crmId
hasPaymentMethod
additionalMetaData # optional
}
subscriptionDecisionStrategy
subscription {
refId
status
plan {
refId
}
}
}
}
Variables
{
"input": {
"refId": "customer-id",
"name": "Acme",
"email": "[email protected]",
"couponRefId": "coupon-id",
"billingInformation": {
"language": "en",
"timezone": "America/New_York",
"billingAddress": {
"country": "US",
"city": "New York",
"state": "NY",
"addressLine1": "123 Main Street",
"addressLine2": "Apt. 1",
"phoneNumber": "+1 212-499-5321",
"postalCode": "10164"
},
"shippingAddress": {
"country": "US", // country format must be in the ISO-3166-1 format
"city": "New York",
"state": "NY",
"addressLine1": "123 Main Street",
"addressLine2": "Apt. 1",
"phoneNumber": "+1 212-499-5321",
"postalCode": "10164"
}
},
"additionalMetaData": {
"key": "value"
},
"subscriptionParams": {
"planId": "plan-revvenu-basic"
}
},
}
Response
{
"data": {
"provisionCustomer": {
"customer": {
"refId": "customer-id",
"name": "Acme",
"email": "[email protected]",
"createdAt": "2022-09-22T08:00:28.965Z",
"billingId": null,
"crmId": null,
"hasPaymentMethod": false,
"additionalMetaData": {
"key": "value"
}
},
"subscriptionDecisionStrategy": "REQUESTED_PLAN",
"subscription": {
"refId": "subscription-plan-revvenu-basic-7b5a40",
"status": "ACTIVE",
"plan": {
"refId": "plan-revvenu-basic"
}
}
}
}
}
Updating customers
Customer information can also be updated whenever you like assuming it already exists, for example: In order to update the customer's email, you only need to send the new email value without the rest of the customer.
Due to the fact that the customer's billing information is not persisted on Stigg's servers, in order to update it, the entire billing information object must be passed each time.
Query
mutation UpdateOneCustomer($input: UpdateCustomerInput!) {
updateOneCustomer(input: $input) {
refId
name
email
createdAt
billingId
crmId
hasPaymentMethod
additionalMetaData
}
}
Variables
{
"input": {
"email": "[email protected]",
"name": "Acme",
"refId": "customer-id",
"billingInformation": {
"language": "en",
"timezone": "America/New_York",
"currency":"USD",
"taxIds": [
{"type": "...", "value": "..."}
],
},
"additionalMetaData": {
"key": "value"
}
}
}
Response
{
"data": {
"updateOneCustomer": {
"refId": "customer-id",
"name": "Acme",
"email": "[email protected]",
"createdAt": "2022-08-24T20:37:46.194Z",
"billingId": null,
"crmId": null,
"hasPaymentMethod": false,
"additionalMetaData": {
"key": "value"
}
}
}
}
Getting customer data
Query
fragment CouponFragment on Coupon {
id
discountValue
additionalMetaData
refId
name
description
createdAt
updatedAt
billingId
type
status
}
fragment PriceFragment on Price {
billingModel
billingPeriod
price {
amount
currency
}
feature {
featureUnits
featureUnitsPlural
displayName
refId
}
}
fragment TotalPriceFragment on CustomerSubscriptionTotalPrice {
subTotal {
amount
currency
}
total {
amount
currency
}
}
fragment AddonFragment on Addon {
id
refId
displayName
description
additionalMetaData
}
fragment PlanFragment on Plan {
id
refId
displayName
description
additionalMetaData
}
fragment SubscriptionFragment on CustomerSubscription {
id
startDate
endDate
trialEndDate
cancellationDate
effectiveEndDate
status
refId
currentBillingPeriodEnd
additionalMetaData
prices {
usageLimit
price {
...PriceFragment
}
}
totalPrice {
...TotalPriceFragment
}
pricingType
plan {
...PlanFragment
}
addons {
id
quantity
addon {
...AddonFragment
}
}
}
fragment PromotionalEntitlementFragment on PromotionalEntitlement {
status
usageLimit
featureId
hasUnlimitedUsage
resetPeriod
endDate
isVisible
feature {
displayName
description
refId
}
}
fragment CustomerFragment on Customer {
id
name
email
createdAt
updatedAt
hasPaymentMethod
refId
billingId
additionalMetaData
coupon {
...CouponFragment
}
promotionalEntitlements {
...PromotionalEntitlementFragment
}
subscriptions {
...SubscriptionFragment
}
}
query GetCustomerByRefId($filter: CustomerFilter) {
customers(filter: $filter) {
edges {
node {
...CustomerFragment
}
}
}
}
Variables
{
"filter": {
"refId": {
"eq": "customer-id"
}
}
}
Response
{
"data": {
"customers": {
"edges": [
{
"node": {
"id": "a1c08d83-4175-4402-99de-0924a158eaa1",
"name": "Acme",
"email": "[email protected]",
"createdAt": "2022-08-24T20:37:46.194Z",
"updatedAt": "2022-08-24T21:43:50.593Z",
"hasPaymentMethod": false,
"refId": "customer-id",
"billingId": "",
"additionalMetaData": {
"key": "value"
},
"coupon": null,
"promotionalEntitlements": [],
"subscriptions": [
{
"id": "0136d54d-c34d-435d-b53c-e0e6f358608a",
"startDate": "2022-08-24T21:25:51.921Z",
"endDate": null,
"trialEndDate": null,
"cancellationDate": null,
"effectiveEndDate": null,
"status": "ACTIVE",
"refId": "subscription-plan-revvenu-basic-e24ddb",
"currentBillingPeriodEnd": "2022-09-24T21:25:51.921Z",
"additionalMetaData": {
"key": "value"
},
"prices": [],
"totalPrice": null,
"pricingType": "FREE",
"plan": {
"id": "08b249b1-5d15-4d09-a9f8-da4af00836d5",
"refId": "plan-revvenu-basic",
"displayName": "Basic",
"description": null,
"additionalMetaData": null
},
"addons": []
},
{
"id": "b55b6164-19c2-463c-b326-5606fe561bb9",
"startDate": "2022-08-24T21:23:36.291Z",
"endDate": null,
"trialEndDate": null,
"cancellationDate": "2022-08-24T21:25:52.278Z",
"effectiveEndDate": "2022-08-24T21:25:52.278Z",
"status": "CANCELED",
"refId": "subscription-plan-revvenu-basic-aa98bd",
"currentBillingPeriodEnd": "2022-09-24T21:23:36.291Z",
"additionalMetaData": {
"key": "value"
},
"prices": [],
"totalPrice": null,
"pricingType": "FREE",
"plan": {
"id": "08b249b1-5d15-4d09-a9f8-da4af00836d5",
"refId": "plan-revvenu-basic",
"displayName": "Basic",
"description": null,
"additionalMetaData": null
},
"addons": []
},
{
"id": "7d4be2d9-ffc8-42f4-a79e-19960b631ef2",
"startDate": "2022-08-24T21:00:13.000Z",
"endDate": null,
"trialEndDate": null,
"cancellationDate": "2022-08-24T21:23:36.622Z",
"effectiveEndDate": "2022-08-24T21:23:36.622Z",
"status": "CANCELED",
"refId": "subscription-plan-revvenu-basic-fc1e1d",
"currentBillingPeriodEnd": "2023-08-24T21:00:13.000Z",
"additionalMetaData": null,
"prices": [],
"totalPrice": null,
"pricingType": "FREE",
"plan": {
"id": "08b249b1-5d15-4d09-a9f8-da4af00836d5",
"refId": "plan-revvenu-basic",
"displayName": "Basic",
"description": null,
"additionalMetaData": null
},
"addons": []
}
]
}
}
]
}
}
}
Creating subscriptions
When a customer subscribes to a new plan (free, paid, trial, etc.), create the subscription in Stigg.
Query
mutation CreateSubscription($input: SubscriptionInput!) {
createSubscription(subscription: $input) {
id
refId
status
additionalMetaData
plan {
id
refId
}
addons {
quantity
addon {
id
refId
}
}
customer {
id
refId
}
}
}
Variables
{
"input": {
"customerId": "customer-id",
"planId": "plan-revvenu-basic",
"billingPeriod": "MONTHLY",
"addons": [
{
"addonId": "addon-extra-stuff",
"quantity": 2
}
],
"additionalMetaData": {
"key": "value"
}
}
}
Response
{
"data": {
"createSubscription": {
"id": "e8ca2feb-e57e-4e93-9007-f14814524944",
"refId": "subscription-plan-revvenu-essentials-65768c",
"status": "PAYMENT_PENDING",
"additionalMetaData": {
"key": "value"
},
"plan": {
"id": "3b0c9144-f6ea-4a39-af7b-2c9dda38a813",
"refId": "plan-revvenu-essentials"
},
"addons": [
{
"quantity": 2,
"addon": {
"id": "83763342-93af-4ea7-995f-9598be7393f0",
"refId": "addon-10-campaigns"
}
}
],
"customer": {
"id": "8e527bc0-9822-4b02-acbd-dadec77a01b2",
"refId": "customer-9a88b4"
}
}
}
}
- A customer can have both a non-trial (free or paid) subscription and trial subscription to different plans of the same product in parallel - this logic allows customers to trial a higher tier plan, while still paying for an existing plan.
- When the customer has a trial subscription for plan X of product A and a new subscription is created for the same plan, the new subscription will be created as non-trial (paid) subscription - this logic follows an upgrade flow of a trial subscription to a paid subscription of a specific plan.
- Except in the above-mentioned cases, when a customer has an active subscription for product X, and another subscription for the same product is created with start date S, the existing subscription will automatically be cancelled and the new subscription will start on start date S.
It's also possible to explicitly skip the trial period of the selected plan by providing theskipTrial: true
parameter to theCreateSubscription
mutation.
Updating subscriptions
Updating an existing subscription, this can be used to update the feature quantity that the customer is subscribed for.
Query
mutation UpdateOneSubscription($input: UpdateSubscriptionInput!) {
updateOneSubscription(input: $input) {
id
refId
status
additionalMetaData
plan {
id
refId
}
addons {
quantity
addon {
id
refId
}
}
customer {
id
refId
}
}
}
Variables
{
"input": {
"refId": "subscription-plan-professional-4dfecf",
"unitQuantity": 5,
}
}
Response
{
"data": {
"updateOneSubscription": {
"id": "e8ca2feb-e57e-4e93-9007-f14814524944",
"refId": "subscription-plan-professional-4dfecf",
"status": "PAYMENT_PENDING",
"additionalMetaData": {
"key": "value"
},
"plan": {
"id": "3b0c9144-f6ea-4a39-af7b-2c9dda38a813",
"refId": "plan-revvenu-essentials"
},
"addons": [
{
"quantity": 2,
"addon": {
"id": "83763342-93af-4ea7-995f-9598be7393f0",
"refId": "addon-10-campaigns"
}
}
],
"customer": {
"id": "8e527bc0-9822-4b02-acbd-dadec77a01b2",
"refId": "customer-9a88b4"
}
}
}
}
Cancel subscription
Query
mutation CancelSubscription($input: SubscriptionCancellationInput!) {
cancelSubscription(input: $input) {
refId
status
additionalMetaData
}
}
Variables
{
"input": {
"subscriptionRefId": "subscription-id",
"subscriptionCancellationTime": "IMMEDIATE"
}
}
Response
{
"data": {
"cancelSubscription": {
"refId": "subscription-plan-revvenu-essentials-5f7470",
"status": "CANCELED",
"additionalMetaData": {
"key": "value"
}
}
}
}
Subscription cancellation will take place according to the defined product behavior.
Getting the entitlement of a customer for a specific feature
Used to check if the customer has access to a feature, the usage limit, and the current usage.
Query
query GetEntitlement($query: FetchEntitlementQuery!) {
entitlement(query: $query) {
isGranted
feature {
refId
displayName
featureUnits
featureUnitsPlural
featureType
meterType
description
}
currentUsage
customerId
accessDeniedReason
requestedUsage
usageLimit
hasUnlimitedUsage
nextResetDate
resetPeriod
}
}
Variables
{
"query": {
"customerId": "customer-id",
"featureId": "feature-01-templates",
"options": {
"requestedUsage": 0
}
}
}
Response
{
"data": {
"entitlement": {
"isGranted": true,
"feature": {
"refId": "feature-01-templates",
"displayName": "Templates",
"featureUnits": "Template",
"featureUnitsPlural": "Templates",
"featureType": "NUMBER",
"meterType": "Fluctuating",
"description": null
},
"currentUsage": 0,
"customerId": "a1c08d83-4175-4402-99de-0924a158eaa1",
"accessDeniedReason": null,
"requestedUsage": 0,
"usageLimit": 3,
"hasUnlimitedUsage": false,
"nextResetDate": null,
"resetPeriod": null
}
}
}
Getting all of the entitlements of a customer
Used to check to what features the customer has access to, the usage limit , and the current usage of each entitlement.
Query
query GetEntitlements($query: FetchEntitlementsQuery!) {
cachedEntitlements(query: $query) {
feature {
refId
displayName
featureUnits
featureUnitsPlural
featureType
meterType
description
}
currentUsage
customerId
usageLimit
hasUnlimitedUsage
nextResetDate
resetPeriod
}
}
Variables
{
"query": {
"customerId": "customer-id"
}
}
Response
{
"data": {
"cachedEntitlements": [
{
"feature": {
"refId": "feature-03-custom-domain",
"displayName": "Custom domain",
"featureUnits": null,
"featureUnitsPlural": null,
"featureType": "BOOLEAN",
"meterType": "None",
"description": null
},
"currentUsage": 0,
"customerId": "96ed6019-031a-4c52-bc41-b8fa3b5d86c5",
"usageLimit": null,
"hasUnlimitedUsage": false,
"nextResetDate": null,
"resetPeriod": null
},
{
"feature": {
"refId": "feature-04-analytics",
"displayName": "Analytics",
"featureUnits": null,
"featureUnitsPlural": null,
"featureType": "BOOLEAN",
"meterType": "None",
"description": null
},
"currentUsage": 0,
"customerId": "96ed6019-031a-4c52-bc41-b8fa3b5d86c5",
"usageLimit": null,
"hasUnlimitedUsage": false,
"nextResetDate": null,
"resetPeriod": null
},
{
"feature": {
"refId": "feature-01-templates",
"displayName": "Templates",
"featureUnits": "Template",
"featureUnitsPlural": "Templates",
"featureType": "NUMBER",
"meterType": "Fluctuating",
"description": null
},
"currentUsage": 3,
"customerId": "96ed6019-031a-4c52-bc41-b8fa3b5d86c5",
"usageLimit": 5,
"hasUnlimitedUsage": false,
"nextResetDate": null,
"resetPeriod": null
},
{
"feature": {
"refId": "feature-02-campaigns",
"displayName": "Campaigns",
"featureUnits": "Campaign",
"featureUnitsPlural": "Campaigns",
"featureType": "NUMBER",
"meterType": "Incremental",
"description": null
},
"currentUsage": 10,
"customerId": "96ed6019-031a-4c52-bc41-b8fa3b5d86c5",
"usageLimit": 12,
"hasUnlimitedUsage": false,
"nextResetDate": "2022-09-21T00:00:00.000Z",
"resetPeriod": "MONTH"
}
]
}
}
Reporting usage measurements to Stigg
Stigg API supports reporting customer usage measurements for metered features.
The reported usage amount will be used to track, limit and bill the customer's usage of metered features.
For features with a fluctuating meter you can also pass a negative value to decrement the usage amount.
Query
mutation CreateUsageMeasurement($input: UsageMeasurementCreateInput!) {
createUsageMeasurement(usageMeasurement: $input) {
id
}
}
Variables
{
"input": {
"value": 5,
"customerId": "customer-id",
"featureId": "feature-02-campaigns"
}
}
Response
{
"data": {
"createUsageMeasurement": {
"id": "05e3a286-acaa-42cd-b76b-b49befbd5113"
}
}
}
- Reporting of measurements to Stigg should be done only after the relevant resources have been provisioned in your application.
- To ensure that the provisioned resources are aligned with the measurements that are reported to Stigg, ensure that customers are not allowed to allocate new resources until an acknowledgement about the processed measurement is received from the Stigg backend.
Validating that a measurement was successfully reported to Stigg is also possible in the customer details section of the relevant customer in the Stigg Cloud Console.
Initiating a checkout
If any of the billing integrations (such as Stripe) is active, you'll need to make sure the customer has a valid payment method before attempting to create a subscription for a paid plan or add-on.
You can check if a customer has a valid payment method by getting the customer data first.
In order to capture the customer's payment information, you can leverage the initiateCheckout
mutation to start a checkout session which will call the underlying checkout flow of the billing solution that's integrated with Stigg. For example, if Stripe is integrated with Stigg, Stigg will create a Stripe Checkout session for the provided catalog items and return the session's URL as the checkoutUrl
field.
You'll need to redirect the customer to the checkoutUrl to complete the checkout process.
Completing the checkout session will result in creating a subscription in both Stripe and Stigg.
After the checkout is complete, the user will be redirected to the provided successUrl
or errorUrl
according to the result of the checkout process.
Query
mutation InitiateCheckout($input: InitiateCheckoutInput!) {
initiateCheckout(input: $input) {
checkoutUrl
}
}
Variables
{
"input": {
"customerId": "customer-id",
"planId": "plan-id",
"billingPeriod": "MONTHLY",
"unitQuantity": 4, // optional, pass this parameter in order to anchor the number of units in the checkout page for subscriptions with per-unit pricing
"addons": [ // optional
{
"addonId": "addon-id",
"quantity": 1
}
],
"successUrl": "<https://myapp.com/checkout-success>",
"cancelUrl": "<https://myapp.com/checkout-error>",
}
}
Response
{
"data": {
"initiateCheckout": {
"checkoutUrl": "https://checkout.stripe.com/pay/cs_test_b1C2hSgpv6Fc4F1xxsIc8Vs7kg8L36zKM8cYm9lD9L4JEleVxFJdQxf2DX#fidkdWxOYHwnPyd1blpxYHZxWjA0Tzx1TlNJSHxCYEZGd1BHPU1kM0JAXVFHfXdrREhnQ3VJdldAS1MwZjRkNGxxcWBVf09SSE0zRzBcYTN3cXNkbFdMQnI0V3ZrN0toSGc3NnB9QEdBPVJMNTVzM3NpdnVDSycpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPydocGlxbFpscWBoJyknYGtkZ2lgVWlkZmBtamlhYHd2Jz9xd3BgKSd2cXdsdWBEZmZqcGtxJz8nZGZmcVo0Tkx0a3JANGJTUTd%2Fcl9TJ3gl"
}
}
}
Estimate subscription cost
You can estimate the subscription cost using the estimateSubscription
method.
This can help the customer to understand the costs before paying.
Query
mutation EstimateSubscription($input: EstimateSubscriptionInput!) {
estimateSubscription(input: $input) {
subTotal {
amount
currency
}
total {
amount
currency
}
billingPeriodRange {
start
end
}
proration {
prorationDate
credit {
amount
currency
}
debit {
amount
currency
}
}
}
}
Variables
{
"input": {
"customerId": "customer-demo-01",
"billingPeriod": "MONTHLY",
"planId": "plan-revvenu-essentials",
"priceUnitAmount": 4,
"addons": [
{
"addonId": "addon-10-campaigns",
"quantity": 2
}
],
"startDate": null,
"billingInformation": {
"taxRateIds": null
}
}
}
Result
{
"data": {
"estimateSubscription": {
"subTotal": {
"amount": 30,
"currency": "USD"
},
"total": {
"amount": 30,
"currency": "USD"
},
"billingPeriodRange": {
"start": "2022-10-26T15:32:57.016Z",
"end": "2022-11-26T15:32:57.016Z"
},
"proration": null
}
}
}
You can also estimate the cost of updating an existing subscription using the updateSubscription
method, which also returns a breakdown of the proration amounts:
Query
mutation EstimateSubscriptionUpdate($input: EstimateSubscriptionUpdateInput!) {
estimateSubscriptionUpdate(input: $input) {
subTotal {
amount
currency
}
total {
amount
currency
}
billingPeriodRange {
start
end
}
proration {
prorationDate
credit {
amount
currency
}
debit {
amount
currency
}
}
}
}
Variables
{
"input": {
"subscriptionId": "subscription-plan-revvenu-growth-da6324",
"unitQuantity": 7,
"addons": [
{"addonId": "addon-10-campaigns", "quantity": 2 }
]
}
}
Result
{
"data": {
"estimateSubscriptionUpdate": {
"subTotal": {
"amount": 7,
"currency": "USD"
},
"total": {
"amount": 7,
"currency": "USD"
},
"billingPeriodRange": {
"start": "2022-10-26T17:07:17.000Z",
"end": "2022-11-26T17:07:17.000Z"
},
"proration": {
"prorationDate": "2022-10-26T17:08:23.000Z",
"credit": {
"amount": -10,
"currency": "USD"
},
"debit": {
"amount": 17,
"currency": "USD"
}
}
}
}
}
Getting available coupons
Query
fragment CouponFragment on Coupon {
id
discountValue
type
additionalMetaData
refId
name
description
createdAt
updatedAt
billingId
type
status
}
query FetchCoupons($filter: CouponFilter) {
coupons(filter: $filter, sorting: $sorting, paging: $paging) {
edges {
node {
...CouponFragment
}
}
}
}
Variables
{
"filter": {
"status": {
"eq": "ACTIVE",
},
},
}
Response
{
"data": {
"coupons": {
"edges": [
{
"node": {
"id": "d7644ee3-6370-444e-bd0a-f73ed8f9cc76",
"discountValue": 20,
"type": "PERCENTAGE",
"additionalMetaData": null,
"refId": "coupon-215e17",
"name": "VIP",
"description": null,
"createdAt": "2022-08-25T00:27:56.368Z",
"updatedAt": "2022-08-25T00:27:56.761Z",
"billingId": "TYvB8jF8",
"billingLinkUrl": "https://dashboard.stripe.com/test/coupons/TYvB8jF8",
"status": "ACTIVE"
}
}
]
}
}
}
Migrating subscriptions to the latest plan and add-on version
When changes to plans and add-ons are rolled out only to new subscriptions, grandfathering takes place. In order to prevent a SKU sprawl, Stigg allows you to manually migrate subscriptions to the latest plan and add-on version on a subscription-by-subscription basis.
- Subscription will be migrated immediately upon completion of the GraphQL request.
- When the current price of the subscription is different than the latest published package version, during the migration the customer will be charged or credited the prorated amount until the end of the current billing period depending on whether the latest price is more expensive or cheaper than the current subscription price.
Query
mutation MigrateSubscriptionToLatest($input: SubscriptionMigrationInput!) {
migrateSubscriptionToLatest(input: $input) {
subscriptionId
}
}
Variables
{
"input": {
"subscriptionId": "subscription-plan-revvenu-basic-6fb76d"
}
}
Response
{
"data": {
"migrateSubscriptionToLatest": {
"subscriptionId": "subscription-plan-revvenu-basic-6fb76d"
}
}
}
Full API reference
Updated about 1 month ago