Skip to content

Instantly share code, notes, and snippets.

@blakejakopovic
Created April 11, 2023 15:15
Show Gist options
  • Save blakejakopovic/a0deee4c945c122a59ed2dcf442d2e2a to your computer and use it in GitHub Desktop.
Save blakejakopovic/a0deee4c945c122a59ed2dcf442d2e2a to your computer and use it in GitHub Desktop.
NIP-XX - My Services

Nostr 'My Services' Event Kind (Draft/Experiment)

A way to support in-app management of services with subscriptions and credits where a payment is due (I guess it can be free too?).

Client UX

A client app can query for these events and show a list of services that are active or have credit remaining. They can show a list of expired (or no credit left) services as well. Clicking a service can allow you to make a payment based on the payment options provided.

What to support

  • Current balance (optional if expiry exists, else mandatory)
  • Current expiry (optional for balance): Represents payment due by
  • Get Usage data/Summary?
  • Ability to pay renewal, or prepaid credits
  • Ability to get a some kind of receipt (maybe this is just an updated balance/renewal event being received
  • Request a new renewal (if old has expired)

Questions

  • Can it support a coupon or special discount token?
  • How to prevent flood abuse?
  • How often should balances be pushed into the network (we likely don't need every second - and client apps can refresh when you try view the My Services view. Maybe it can trigger a refresh request directly.

Event Types

  • Request Balance/Renewal refresh
  • Receive Balance/Renewal
  • Request Usage data
  • Receive Usage data

Poor Mans Mocked API

Current
  balance: 11111111 (unit name?)
  Expiry: UNIX_TIME
   
Previous Payment (maybe last 3 or 10..?)
previous_payments {
  payment_date: UNIX TIME
  payment_details: {
       {
        type: credit/period
	quantity: 10000 (units?)
        amount: 10000
        currency: btc-sat
        }
  payment_notes: Maybe a custom message or comment from the vendor
  }
}

Payment Options (typically credits OR period)
credits [
       {
	quantity: 10000 (units?)
        amount: 10000
        currency: btc-sat
        },
]
periods[
       {
          new_expiry: UNIX_TIME (1m)
          amount: 10000
	  currency: btc-sat
          invoice_data: 
        },
       {
          new_expiry: UNIX_TIME (3m)
          amount: 25000
	  currency: btc-sat
          invoice_data: 
        },
       {
          new_expiry: UNIX_TIME (6m)
          amount: 47000
	  currency: btc-sat
          invoice_data: 
        }
]
offer_expiry: UNIX TIME: Time at which payment is no longer possible at current prices
@blakejakopovic
Copy link
Author

Other notes so far.

Units could be data storage so bytes (storage or available to upload)
Usage could be N bytes / M bytes

  • a paid service type (subscription, credit based)
  • provider info
    • name of provider
    • icon?
    • link to website
  • where to manage and top up
  • if it's a subscription:
    • expiry date
    • type (free trial, monthly, yearly)
    • renewal cost, optional (unit + amount)
  • if it's a credit based service:
    • credit type (translations, events, ...)
    • amount remaining
  • subscription info link (say how much credits are consumed etc)

Google Mobile Data Sharing Plan
https://developers.google.com/mobile-data-plan/agent_api_specification

{
  "plans": [{
    "planName": "ACME1",
    "planId": "1",
    "planCategory": "PREPAID",
    "expirationTime": "2017-01-29T01:00:03.14159Z", // req.
    "planModules": [{
      "moduleName": "Giga Plan", // req.
      "trafficCategories": ["GENERIC"],
      "expirationTime": "2017-01-29T01:00:03.14159Z", // req.
      "overUsagePolicy": "BLOCKED",
      "maxRateKbps": "1500",
      "description": "1GB for a month", // req.
      "coarseBalanceLevel": "HIGH_QUOTA"
    }]
  }],
  "languageCode": "en-US", // req.
  "expireTime": "2018-06-14T08:41:27-07:00", // req.
  "updateTime": "2018-06-07T07:41:22-07:00", // req.
  "title": "Prepaid Plan"
  "planInfoPerClient": {
    "youtube": {
      "rateLimitedStreaming": {
        "maxMediaRateKbps": 256
      }
    }
  }
}
{
    "offers": [
      {
        "planName": "ACME Red", // req.
        "planId": "turbulent1", // req.
        "planDescription": "Unlimited Videos for 30 days.", // req.
        "promoMessage": "Binge watch videos.",
        "languageCode": "en_US", // req.
        "overusagePolicy": "BLOCKED",
        "cost": { // req.
          "currencyCode": "INR",
          "units": "300",
          "nanos": 0
        },
        "duration": "2592000s",
        "offerContext": "YouTube",
        "trafficCategories": ["VIDEO"],
        "quotaBytes": "9223372036850",
        "filterTags": ["repurchase", "all"]
      }
    ],
    "filters" : [
      {
        "tag": "repurchase",
        "displayText": "REPURCHASE PLANS"
      },
      {
        "tag": "all",
        "displayText": "ALL PLANS"
      }
    ]
    "expireTime": "2019-03-04T00:06:07Z" // req.
}
{
  "transactionStatus": "SUCCESS",

  "purchase": {
    "planId": string,               // copied from request. (req.)
    "transactionId": string,        // copied from request. (req.)
    "transactionMessage": string,   // status message. (opt.)
    "confirmationCode": string,     // DPA-generated confirmation code
                                    // for successful transaction. (opt.)
    "planActivationTime" : string,  // Time when plan will be activated,
                                    // in timestamp format. (opt.)
  },

  // walletInfo is populated with the balance left in the user's account.
  "walletBalance": {
    "currencyCode": string,       // 3-letter currency code defined in ISO 4217.
    "units": string,              // Whole units of the currency amount.
    "nanos": number               // Number of nano units of the amount.
  }
}

https://api-reference.checkout.com/#operation/requestAPaymentOrPayout

{
  "source": {
    "type": "token",
    "token": "tok_4gzeau5o2uqubbk6fufs3m7p54"
  },
  "amount": 6540,
  "currency": "USD",
  "payment_type": "Recurring",
  "reference": "ORD-5023-4E89",
  "description": "Set of 3 masks",
  "capture": true,
  "capture_on": "2019-09-10T10:11:12Z",
  "customer": {
    "id": "cus_udst2tfldj6upmye2reztkmm4i",
    "email": "brucewayne@gmail.com",
    "name": "Bruce Wayne",
    "phone": {
      "country_code": "+1",
      "number": "415 555 2671"
    }
  },
  "billing_descriptor": {
    "name": "SUPERHEROES.COM",
    "city": "GOTHAM"
  },
  "shipping": {
    "address": {
      "address_line1": "Checkout.com",
      "address_line2": "90 Tottenham Court Road",
      "city": "London",
      "state": "London",
      "zip": "W1T 4TJ",
      "country": "GB"
    },
    "phone": {
      "country_code": "+1",
      "number": "415 555 2671"
    }
  },
  "3ds": {
    "enabled": true,
    "attempt_n3d": true,
    "eci": "05",
    "cryptogram": "AgAAAAAAAIR8CQrXcIhbQAAAAAA=",
    "xid": "MDAwMDAwMDAwMDAwMDAwMzIyNzY=",
    "version": "2.0.1"
  },
  "previous_payment_id": "pay_fun26akvvjjerahhctaq2uzhu4",
  "risk": {
    "enabled": false
  },
  "success_url": "http://example.com/payments/success",
  "failure_url": "http://example.com/payments/fail",
  "payment_ip": "90.197.169.245",
  "recipient": {
    "dob": "1985-05-15",
    "account_number": "5555554444",
    "zip": "W1T",
    "last_name": "Jones"
  },
  "metadata": {
    "coupon_code": "NY2018",
    "partner_id": 123989
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment