Working with Invoices

Once you have Accounts established it's time to start issuing Invoices. Invoices are simply a list of items, services, taxes, fees, discounts etc. which a seller is offering for payment in Dogecoin.

📚 Wikipedia: An invoice, bill or tab is a commercial document issued by a seller to a buyer relating to a sale transaction and indicating the products, quantities, and agreed-upon prices for products or services the seller had provided the buyer.

As mentioned previously Gigawallet is not your general-purpose user database, just so it is not your general purpose shopping-cart either. For this reason Invoices are specifically designed to encourage you to have finalised all purchase decisions before issuing an Invoice as the final step when your user wants to pay in Dogecoin. Once created an invoice cannot be directly updated (this is a design decision!) Gigawallet is a payment system for Dogecoin.

Parts of an Invoice

An invoice is created via the POST /account/:foreignID/invoice endpoint and consists of a list of items along with metadata about the status of the payment. Here is an example invoice:

{
  "id": "DNBVSoHLhX4gQiGLdZJhXMe7XZWuD7orVo",
  "items": [
    {
      "type": "item",
      "name": "A segment of Toblerone",
      "sku": "TOB001",
      "description": "You can share my Toblerone, for 1 Dogecoin!",
      "value": "1",
      "quantity": 1,
      "image_link": ""
    }
  ],
  "created": "2023-08-17T15:40:13.935244+10:00",
  "total": "1",
  "pay_to_address": "DNBVSoHLhX4gQiGLdZJhXMe7XZWuD7orVo",
  "part_payment_detected": false,
  "total_payment_detected": false,
  "total_payment_confirmed": false,
  "payment_unconfirmed": false,
  "estimate_seconds_to_confirm": 0
}

id

This is a unique ID, it also happens to be the public child address generated from the account HD wallet for this invoice. You'll notice it's identical to pay_to_address for that reason, you can use this to reference the invoice in future API calls or as a unique identifier for the invoice in your own system.

items

Items is an array of line items that get passed in when the invoice is created, Items have a value which is a decimal amount of Dogecoin, as a string, per item. This is multiplied by quantity and summed across all items to derrive the invoice total.

Items also have a type which must be one of:

  • item
  • tax
  • fee
  • shipping
  • discount

These types are primarily used to distinguish line-items in UI, so that taxes, shipping and fees can be grouped separately. We do validate that all item values are a positve amount, except for items of type discount which must be a negative amount.

total

This is the total calculated amount owing for the invoice to be considered paid, and is calculated as the sum of all item values * quantity. This is a decimal value as a string.

pay_to_address

This is the dogecoin address for recieving invoice payment.

part_payment_detected

This is a boolean flag that will be set when GigaWallet first detects any kind of payment in a block. This may or may not be the total amount owing.

total_payment_detected

This is a boolean flag that will be set when GigaWallet first detects a payment in a block that would complete the total amount owing.

total_payment_confirmed

This is a boolean flag that will be set when GigaWallet detects that required_confirmations have been met on the network, this is the best means of determining payment has been made.

payment_unconfirmed

This boolean will only be set in the event that required_confirmations has been met and confirmed, however the blockchain has forked and eliminated your payment. This should only occur in the event that you are using a very low required_confirmations count.

⚠️ Note: What should you do in this event? Did I just lose my Dogecoin?

GigaWallet cannot hide you from the reality of the blockchain and the potential for soft-forks, in day to day running we see these tip-reorgs happening semi regularly and removing 1 or at most 2 blocks of confirmation. In the event that a tip-reorg happens and that decrements the required number of confirmations or even eliminates your payment, it is highly likely that the transaction will be included in a new block shortly. GigaWallet will then re-issue and re-set the appropriate events / flags on the new tip.

It is possible that the payer has intentionally issued a double-spend transaction hoping to fake payment, we recommend that you set a required_confirmations value commensurate with the amount of Dogecoin in your invoice and the appropriate level of risk. If you are selling someone a Coffee for 30 Dogecoin perhaps a 1 block confirmation is fine, if you are selling a million dollar house, there is no reason not to wait for 20-30 confirmations, the ink will still be wet on the page anyway.

estimate_seconds_to_confirm

Once an intial payment has been seen, this value will be an estimate of the remaining seconds before confirmation based on the required_confirmations set for this Invoice. This is useful for anyone using a poll-method to query payment as you can roughly predict the wait-time. If no payment has been seen or the invoice is already paid this value will be 0.

Admin API

POST /account/:foreignID/invoice

_Create an Invoice

:foreignID is the unique identifier from your system which you used to create an account.

REQUEST BODY:

Expected POST Body:

{
  "items": [
    {
      "name": "Dogecoin Sticker",
      "value": "100.00",
      "quantity": 1,
      "type": "item"
    }
  ],
  "required_confirmations": 3
}

RESPONSE BODY:

{
  "id": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
  "items": [
    {
      "type": "item",
      "name": "Dogecoin Sticker",
      "sku": "",
      "description": "",
      "value": "100",
      "quantity": 1,
      "image_link": ""
    }
  ],
  "created": "2023-08-30T16:49:51.705419+10:00",
  "total": "100",
  "pay_to_address": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
  "part_payment_detected": false,
  "total_payment_detected": false,
  "total_payment_confirmed": false,
  "payment_unconfirmed": false,
  "estimate_seconds_to_confirm": 0
}

GET /account/:foreignID/invoice/:invoiceID

Get an Invoice for a specific account

:foreignID is the unique identifier from your system which you used to create an account. :invoiceID is the unique identifier for an invoice, ie: DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH.

RESPONSE BODY:

{
  "id": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
  "items": [
    {
      "type": "item",
      "name": "Dogecoin Sticker",
      "sku": "",
      "description": "",
      "value": "100",
      "quantity": 1,
      "image_link": ""
    }
  ],
  "created": "2023-08-30T16:49:51.705419+10:00",
  "total": "100",
  "pay_to_address": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
  "part_payment_detected": false,
  "total_payment_detected": false,
  "total_payment_confirmed": false,
  "payment_unconfirmed": false,
  "estimate_seconds_to_confirm": 0
}

GET /account/:foreignID/invoices?limit=100&cursor=0

Enumerate an Invoice for a specific account.

:foreignID is the unique identifier from your system which you used to create an account. limit is the maximum number of records to return. cursor starts at 0, and should be set to the cursor value returned by a previous call.

Those familiar with popular cursor-based APIs such as AWS etc should understand this pattern, it allows for machine-to-machine fetching of all invoices and should not be confused with an offset/limit style API.

The response contains two elements, items which is an array of invoices, and cursor which should be passed to the next invocation. A cursor of 0 indicates there are no further records.

RESPONSE BODY:

{
"items": [
      {
        "id": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
        "items": [
          {
            "type": "item",
            "name": "Dogecoin Sticker",
            "sku": "",
            "description": "",
            "value": "100",
            "quantity": 1,
            "image_link": ""
          }
        ],
        "created": "2023-08-30T16:49:51.705419+10:00",
        "total": "100",
        "pay_to_address": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
        "part_payment_detected": false,
        "total_payment_detected": false,
        "total_payment_confirmed": false,
        "payment_unconfirmed": false,
        "estimate_seconds_to_confirm": 0
      }
  ],
  "cursor": 0
}

Public API

The public invoice APIs are available on a different port which is designed to be exposed to the internet via your proxy or as part of your own API gateway. These APIs can be called by web or mobile clients, with the aim of providing payment info to the payer. We imagine you will use these apis to show the payer a list of items they are purchasing, and to provide details / address / QRcodes etc to facilitate payment.

GET /invoice/:invoiceID

Get an Invoice

:invoiceID is the unique identifier for an invoice, ie: DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH.

RESPONSE BODY:

{
  "id": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
  "items": [
    {
      "type": "item",
      "name": "Dogecoin Sticker",
      "sku": "",
      "description": "",
      "value": "100",
      "quantity": 1,
      "image_link": ""
    }
  ],
  "created": "2023-08-30T16:49:51.705419+10:00",
  "total": "100",
  "pay_to_address": "DMcUQWwMdpdXqiYNiYgCzrM5Wn85dYerQH",
  "part_payment_detected": false,
  "total_payment_detected": false,
  "total_payment_confirmed": false,
  "payment_unconfirmed": false,
  "estimate_seconds_to_confirm": 0
}

GET /invoice/:invoiceID/qr.png

This endpoint does not return JSON, it returns a PNG image of a QR code containing a dogecoin address in the format:

dogecoin:<address>?amount=<amount>&ctx=<dogeconnect url>

The address is the pay_to_address in the invoice. The amount is the total dogecoin in the invoice. The ctx is a URL that points to a dogecoin connect payload.

qr code

This can be directly placed on your payment page and if scanned will load the user's Dogecoin wallet to make a payment for the full amount of the invoice. This could be used in a web interface, or even emailed or mailed with an invoice allowing immediate payment by the recipient.

GET /invoice/:invoiceID/connect

This endpoint returns a dogecoin connect payload which is defined as a new protocol to facilitate payment from a self-custodial wallet without needing access to a relay.

The concept is that a Dogecoin wallet which understands the dogecoin connect protocol can present in it's own UI, an invoice complete with items being purchased and have the user generate a transaction which can be issued back to GigaWallet directly where it will be validated and sent to the mempool.

This will allow GigaWallet to support zero-confirmation payments, aka instant payments which are required for fast-turn-around services such as vending machines, coffee shops, etc.

{
  "version": "0.1",
  "service_name": "Example Dogecoin Store",
  "service_icon_url": "https://example.com/icon.png",
  "service_domain": "example.com",
  "service_key_hash": "...",
  "payload": "eyJ0eXBlIjoiaW52b2ljZSIsInJlcXVlc3...",
  "hash": "..."
}

The JSON body contains a payload which is signed by the issuing store key which can be stored on the client once recognised for the first time. This protocol is still under development and support is incomplete, watch this space!