Collect Your First Payment with a Card Reader

In addition to collecting payments via text messaging, Podium lets you accept in-person credit and debit card payments using a Podium reader. Using card readers in conjunction with Podium means that you can:

  • Consolidate all of your payment methods into one platform.
  • Automate text and email receipts to all customers.

📘

Podium card reader availability

Podium card readers are currently only available in the United States.

At a glance

Invoices enable a business to request and receive payments via Podium. Podium readers are the physical terminal that allows the business to collect payments for card-present transactions.

Podium's Invoice API allows you to manage the complete lifecycle of requesting payment, issuing refunds, and reconciling payments received back into your system of record.

You can use these endpoints to do things like:

  • Create a new invoice to display on a designated payment reader.
  • Update an invoice to either cancel the invoice entirely or refund an amount (full or partial).
  • Retrieve and reconcile payments completed on invoices.

A Podium card reader deployment consists of four main components:

  • Your web-based or mobile application
  • Your backend
  • Podium Invoice API
  • A Podium card reader

What you'll need

  • An active Podium location
  • Client ID and Secret for OAuth access token
  • A Podium card reader

Test Card Numbers

Card NumberBrandCVCDate
4242424242424242VisaAny 3 digitsAny future date
5555555555554444MastercardAny 3 digitsAny future date

Create an invoice

To request a payment to display on a Podium card reader, you will need to provide the following required details:

  • Location UID. The unique identifier of the Podium account associated to the merchant's Payment reader that can be found via the Podium Locations API.
  • Reader UID. The unique identifier of the physical hardware of the card reader.
  • Customer Name. The first and last name of the recipient of the payment request. (For example, "John Doe")
  • Channel Identifier. The email or phone number of the end consumer. This is used to send a receipt and additional messages after the transaction. (For example, a request to leave an online review on a review platform like Google or Facebook).
  • Line Item(s). A minimum of one line item is required. Each line item will consist of detail an amount (required) and a description (optional). An example of the description and amount: Recliner, 20000.
An invoice request via a Podium payment reader

An invoice request via a Podium payment reader

Create an invoice to the payment reader

curl --request POST \
  --url https://api.podium.com/v4/invoices \
  --header 'Content-Type: application/json' \
  --header 'podium-version: 2021.4.1' \
  --data '{"locationUid":"9483748s-3a1c-5537-a31b-442ca560593d","customerName":"John Smith","channelIdentifier":"[email protected]","lineItems":[{"Amount":"20000","Description":"Recliner"}],"readerUid":"46525as-3a1c-5537-a31b-442ca560593d","invoiceNumber":"IN-3240ASD"}'
require 'uri'
require 'net/http'
require 'openssl'

url = URI("https://api.podium.com/v4/invoices")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["podium-version"] = '2021.4.1'
request["Content-Type"] = 'application/json'
request.body = "{\"locationUid\":\"9483748s-3a1c-5537-a31b-442ca560593d\",\"customerName\":\"John Smith\",\"channelIdentifier\":\"[email protected]\",\"lineItems\":[{\"Amount\":\"10000\",\"Description\":\"Chair\"}],\"readerUid\":\"46525as-3a1c-5537-a31b-442ca560593d\",\"invoiceNumber\":\"IN-3240ASD\"}"

response = http.request(request)
puts response.read_body
const options = {
  method: 'POST',
  headers: {'podium-version': '2021.4.1', 'Content-Type': 'application/json'},
  body: JSON.stringify({
    locationUid: '9483748s-3a1c-5537-a31b-442ca560593d',
    customerName: 'John Smith',
    channelIdentifier: '[email protected]',
    lineItems: [{Amount: '10000', Description: 'Chair'}],
    readerUid: '46525as-3a1c-5537-a31b-442ca560593d',
    invoiceNumber: 'IN-3240ASD'
  })
};

fetch('https://api.podium.com/v4/invoices', options)
  .then(response => console.log(response))
  .catch(err => console.error(err));
import requests

url = "https://api.podium.com/v4/invoices"

payload = {
    "locationUid": "9483748s-3a1c-5537-a31b-442ca560593d",
    "customerName": "John Smith",
    "channelIdentifier": "[email protected]",
    "lineItems": [
        {
            "Amount": "10000",
            "Description": "Chair"
        }
    ],
    "readerUid": "46525as-3a1c-5537-a31b-442ca560593d",
    "invoiceNumber": "IN-3240ASD"
}
headers = {
    "podium-version": "2021.4.1",
    "Content-Type": "application/json"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)

Refund an invoice

Occasionally, you may need to issue refunds. For example, if your customer receives the wrong product or isn’t satisfied with the service you’ve provided. You can quickly process refunds by making a request to the Invoices API.

300

Refunding the payment of an invoice

🚧

Note

A payment needs to occur on an invoice in order to request a refund. To test payments, reference Podium's test account information.

The following parameters are required to request a refund to the payment within an invoice.

  • Invoice UID. The internal unique identifier we ascribe to each invoice sent through Podium.
  • Location UID. The unique identifier of the Podium account associated to the merchant's payment reader that can be found via the Podium Locations API.
  • Reason. Available options for reason include duplicate, fraudulent, requested_by_customer, or other.
  • Amount. The amount for the refund represented in cents.
curl --request POST \
  --url https://api.podium.com/v4/invoices/d011ed93-535d-57f8-9da6-d5323e226949/refund \
  --header 'Content-Type: application/json' \
  --header 'podium-version: 2021.4.1' \
  --data '{"locationUid":"9483748s-3a1c-5537-a31b-442ca560593d","reason":"other","amount":1000,"paymentUid":"d011ed93-535d-57f8-9da6-d5323e226338","note":"charged twice for same service"}'
require 'uri'
require 'net/http'
require 'openssl'

url = URI("https://api.podium.com/v4/invoices/d011ed93-535d-57f8-9da6-d5323e226949/refund")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["podium-version"] = '2021.4.1'
request["Content-Type"] = 'application/json'
request.body = "{\"locationUid\":\"9483748s-3a1c-5537-a31b-442ca560593d\",\"reason\":\"other\",\"amount\":1000,\"paymentUid\":\"d011ed93-535d-57f8-9da6-d5323e226338\",\"note\":\"charged twice for same service\"}"

response = http.request(request)
puts response.read_body
const options = {
  method: 'POST',
  headers: {'podium-version': '2021.4.1', 'Content-Type': 'application/json'},
  body: JSON.stringify({
    locationUid: '9483748s-3a1c-5537-a31b-442ca560593d',
    reason: 'other',
    amount: 1000,
    paymentUid: 'd011ed93-535d-57f8-9da6-d5323e226338',
    note: 'charged twice for same service'
  })
};

fetch('https://api.podium.com/v4/invoices/d011ed93-535d-57f8-9da6-d5323e226949/refund', options)
  .then(response => console.log(response))
  .catch(err => console.error(err));
import requests

url = "https://api.podium.com/v4/invoices/d011ed93-535d-57f8-9da6-d5323e226949/refund"

payload = {
    "locationUid": "9483748s-3a1c-5537-a31b-442ca560593d",
    "reason": "other",
    "amount": 1000,
    "paymentUid": "d011ed93-535d-57f8-9da6-d5323e226338",
    "note": "charged twice for same service"
}
headers = {
    "podium-version": "2021.4.1",
    "Content-Type": "application/json"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)

The id returned in the response is an MD5 hash of the contact’s lowercase email address. You can learn more about that here.

Check the invoice status

An invoice will have any of the following statuses:

  • Pending. No payment has been completed on the invoice.
  • Refunded. When the full or a partial amount of the payment has been returned to the end consumer.
  • Paid. When the payment request has been completed and the full amount of all line items within an invoice are paid in full.
  • Canceled. The status for an invoice that is voided and no longer available to collect payments. If the end consumer attempts to make a payment, they will be unable due to the canceled status.

Since we just updated the invoice status with a refund amount, we should expect to see that status as "refunded" in the response.

curl --request GET \
  --url https://api.podium.com/v4/invoices/d011ed93-535d-57f8-9da6-d5323e226949 \
  --header 'Content-Type: application/json' \
  --header 'podium-version: 2021.4.1' \
  --data '{"locationUid":"485red93-535d-57f8-9da6-d5323e226949"}'
require 'uri'
require 'net/http'
require 'openssl'

url = URI("https://api.podium.com/v4/invoices/d011ed93-535d-57f8-9da6-d5323e226949")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["podium-version"] = '2021.4.1'
request["Content-Type"] = 'application/json'
request.body = "{\"locationUid\":\"485red93-535d-57f8-9da6-d5323e226949\"}"

response = http.request(request)
puts response.read_body
const options = {
  method: 'GET',
  headers: {'podium-version': '2021.4.1', 'Content-Type': 'application/json'},
  body: JSON.stringify({locationUid: '485red93-535d-57f8-9da6-d5323e226949'})
};

fetch('https://api.podium.com/v4/invoices/d011ed93-535d-57f8-9da6-d5323e226949', options)
  .then(response => console.log(response))
  .catch(err => console.error(err));
import requests

url = "https://api.podium.com/v4/invoices/d011ed93-535d-57f8-9da6-d5323e226949"

payload = {"locationUid": "485red93-535d-57f8-9da6-d5323e226949"}
headers = {
    "podium-version": "2021.4.1",
    "Content-Type": "application/json"
}

response = requests.request("GET", url, json=payload, headers=headers)

print(response.text)

Reconcile payments

Similar to checking an invoice status, when the invoice status is paid, refunded, or canceled, you can use the updated information of the payment and invoice to sync with your system of record. Reconciliation can be done in two ways.

Invoices API

This is the same process as retrieving an invoice through the Get Invoices API as seen above.

300

Payment received

Invoices Webhook

If your system is set up to be able to listen for webhooks, you can use the Invoice Webhook Events to listen for updates when an invoice is paid.

Congratulations!

Congratulations, you've successfully created an invoice, made a refund to a payment, and then retrieved or listened for its status to reconcile the payment with your system of record.