Skip to content

Latest commit

 

History

History
1241 lines (958 loc) · 33.8 KB

File metadata and controls

1241 lines (958 loc) · 33.8 KB

Item Management

The Item resource provides methods for managing Zai items, which represent transactions or payments between buyers and sellers on your platform.

Overview

Items are the core transactional objects in Zai that represent a payment agreement between a buyer (payin user) and a seller (payout user). Each item tracks:

  • Transaction amount
  • Payment type
  • Buyer and seller information
  • Fees and charges
  • Transaction state and history
  • Wire transfer details (if applicable)

References

Usage

Initialize the Item Resource

# Using the singleton instance (recommended)
items = ZaiPayment.items

# Or create a new instance
items = ZaiPayment::Resources::Item.new

Methods

Create Item

Create a new item (transaction/payment) between a buyer and a seller.

Required Fields

  • name - Name/description of the item
  • amount - Amount in cents (e.g., 10000 = $100.00)
  • payment_type - Payment type (1-7, default: 2 for credit card)
  • buyer_id - Buyer user ID
  • seller_id - Seller user ID

Optional Fields

  • id - Custom unique ID for the item
  • fee_ids - Array of fee IDs to apply
  • description - Detailed description
  • currency - Currency code (e.g., 'AUD', 'USD')
  • custom_descriptor - Custom text for bank statements
  • buyer_url - URL for buyer to access transaction
  • seller_url - URL for seller to access transaction
  • tax_invoice - Whether to generate a tax invoice (boolean)

Example

response = ZaiPayment.items.create(
  name: "Product Purchase",
  amount: 10000, # $100.00 in cents
  payment_type: 2, # Credit card
  buyer_id: "buyer-123",
  seller_id: "seller-456",
  description: "Purchase of premium product XYZ",
  currency: "AUD",
  buyer_url: "https://buyer.example.com",
  seller_url: "https://seller.example.com",
  tax_invoice: true
)

if response.success?
  item = response.data
  puts "Item created: #{item['id']}"
  puts "Amount: #{item['amount']}"
  puts "State: #{item['state']}"
end

Create Item with Custom ID

response = ZaiPayment.items.create(
  id: "my-custom-item-#{Time.now.to_i}",
  name: "Custom ID Product",
  amount: 15000,
  payment_type: 2,
  buyer_id: "buyer-123",
  seller_id: "seller-456"
)

List Items

Retrieve a list of all items with pagination and optional filtering.

# List items with default pagination (10 items)
response = ZaiPayment.items.list

if response.success?
  items_list = response.data
  items_list.each do |item|
    puts "Item: #{item['name']} - $#{item['amount'] / 100.0}"
  end
  
  # Access pagination metadata
  meta = response.meta
  puts "Total items: #{meta['total']}"
end

List with Pagination

# Get 20 items starting from offset 40
response = ZaiPayment.items.list(limit: 20, offset: 40)

Search Items

# Search items by description
response = ZaiPayment.items.list(search: "product")

# Filter by creation date
response = ZaiPayment.items.list(
  created_after: "2024-01-01T00:00:00Z",
  created_before: "2024-12-31T23:59:59Z"
)

# Combine filters
response = ZaiPayment.items.list(
  limit: 50,
  search: "premium",
  created_after: "2024-01-01T00:00:00Z"
)

Show Item

Get details of a specific item by ID.

response = ZaiPayment.items.show("item-123")

if response.success?
  item = response.data
  puts "Item ID: #{item['id']}"
  puts "Name: #{item['name']}"
  puts "Amount: #{item['amount']}"
  puts "Payment Type: #{item['payment_type']}"
  puts "State: #{item['state']}"
  puts "Buyer ID: #{item['buyer_id']}"
  puts "Seller ID: #{item['seller_id']}"
end

Update Item

Update an existing item's details.

response = ZaiPayment.items.update(
  "item-123",
  name: "Updated Product Name",
  description: "Updated product description",
  amount: 12000,
  buyer_url: "https://new-buyer.example.com",
  tax_invoice: false
)

if response.success?
  item = response.data
  puts "Item updated: #{item['id']}"
end

Delete Item

Delete an item by ID.

response = ZaiPayment.items.delete("item-123")

if response.success?
  puts "Item deleted successfully"
end

Show Item Seller

Get the seller (user) details for a specific item.

response = ZaiPayment.items.show_seller("item-123")

if response.success?
  seller = response.data
  puts "Seller: #{seller['first_name']} #{seller['last_name']}"
  puts "Email: #{seller['email']}"
  puts "Country: #{seller['country']}"
end

Show Item Buyer

Get the buyer (user) details for a specific item.

response = ZaiPayment.items.show_buyer("item-123")

if response.success?
  buyer = response.data
  puts "Buyer: #{buyer['first_name']} #{buyer['last_name']}"
  puts "Email: #{buyer['email']}"
end

Show Item Fees

Get the fees associated with an item.

response = ZaiPayment.items.show_fees("item-123")

if response.success?
  fees = response.data
  
  if fees && fees.any?
    puts "Item has #{fees.length} fee(s):"
    fees.each do |fee|
      puts "  #{fee['name']}: $#{fee['amount'] / 100.0}"
    end
  end
end

Show Item Wire Details

Get wire transfer details for an item (useful for bank transfers).

response = ZaiPayment.items.show_wire_details("item-123")

if response.success?
  wire_details = response.data['wire_details']
  
  if wire_details
    puts "Account Number: #{wire_details['account_number']}"
    puts "Routing Number: #{wire_details['routing_number']}"
    puts "Bank Name: #{wire_details['bank_name']}"
  end
end

List Item Transactions

Get all transactions associated with an item.

# List transactions with default pagination
response = ZaiPayment.items.list_transactions("item-123")

if response.success?
  transactions = response.data
  
  transactions.each do |transaction|
    puts "Transaction #{transaction['id']}: #{transaction['state']}"
    puts "  Amount: $#{transaction['amount'] / 100.0}"
    puts "  Type: #{transaction['type']}"
  end
end

# List with custom pagination
response = ZaiPayment.items.list_transactions("item-123", limit: 50, offset: 100)

List Item Batch Transactions

Get all batch transactions associated with an item.

response = ZaiPayment.items.list_batch_transactions("item-123")

if response.success?
  batch_transactions = response.data
  
  batch_transactions.each do |batch|
    puts "Batch #{batch['id']}: #{batch['state']}"
    puts "  Amount: $#{batch['amount'] / 100.0}"
  end
end

# List with pagination
response = ZaiPayment.items.list_batch_transactions("item-123", limit: 25, offset: 50)

Show Item Status

Get the current status of an item.

response = ZaiPayment.items.show_status("item-123")

if response.success?
  status = response.data
  puts "State: #{status['state']}"
  puts "Payment State: #{status['payment_state']}"
  puts "Disbursement State: #{status['disbursement_state']}" if status['disbursement_state']
end

Make Payment

Process a payment for an item using a card account.

Required Parameters

  • account_id - The card account ID to charge (Required)

Optional Parameters

  • device_id - Device identifier for fraud detection
  • ip_address - IP address of the customer
  • cvv - Card CVV for additional verification
  • merchant_phone - Merchant contact phone number
# Make a payment with required parameters
response = ZaiPayment.items.make_payment(
  "item-123",
  account_id: "card_account-456"    # Required
)

if response.success?
  item = response.data
  puts "Payment initiated for item: #{item['id']}"
  puts "State: #{item['state']}"
  puts "Payment State: #{item['payment_state']}"
end

With Optional Parameters

For enhanced fraud protection, include device and IP address information:

response = ZaiPayment.items.make_payment(
  "item-123",
  account_id: "card_account-456",  # Required
  device_id: "device_789",
  ip_address: "192.168.1.1",
  cvv: "123",
  merchant_phone: "+61412345678"
)

if response.success?
  item = response.data
  puts "Payment initiated successfully"
  puts "Item State: #{item['state']}"
  puts "Payment State: #{item['payment_state']}"
end

Make Async Payment

Initiate a card payment with 3D Secure 2.0 (3DS2) authentication support. This endpoint initiates the payment process and returns a payment_token that is required for 3DS2 component initialisation on the client side.

This method is specifically designed for payments that require 3D Secure verification, providing enhanced security for card transactions.

Required Parameters

  • account_id - The card account ID to charge (Required). Note: This is the account ID, not the user ID.

Optional Parameters

  • request_three_d_secure - Customise the 3DS preference for this payment. Allowed values:
    • 'automatic' (default) - 3DS preference is determined automatically by the system
    • 'challenge' - Request a 3DS challenge is presented to the user
    • 'any' - Request a 3DS challenge regardless of the challenge flow

Response

The response includes:

  • payment_id - Unique identifier for the payment
  • payment_token - Token required for 3DS2 component initialisation
  • account_id - The account ID used for the payment
  • items - Complete item details including state, amount, and related information
# Make an async payment with required parameters
response = ZaiPayment.items.make_payment_async(
  "item-123",
  account_id: "card_account-456"  # Required
)

if response.success?
  payment_id = response.data['payment_id']
  payment_token = response.data['payment_token']
  item = response.data['items']
  
  puts "Payment initiated: #{payment_id}"
  puts "Payment token for 3DS2: #{payment_token}"
  puts "Item state: #{item['state']}"
  puts "Amount: $#{item['amount'] / 100.0}"
end

With 3DS Challenge

To explicitly request a 3D Secure challenge:

response = ZaiPayment.items.make_payment_async(
  "item-123",
  account_id: "card_account-456",
  request_three_d_secure: "challenge"
)

if response.success?
  payment_token = response.data['payment_token']
  
  # Use the payment_token to initialise the 3DS2 web component
  puts "Payment token: #{payment_token}"
  puts "Initialise 3DS2 component on client side with this token"
end

Automatic 3DS Determination

When using the default 'automatic' mode, the system determines whether 3DS is required:

response = ZaiPayment.items.make_payment_async(
  "item-123",
  account_id: "card_account-456",
  request_three_d_secure: "automatic"
)

if response.success?
  item = response.data['items']
  payment_token = response.data['payment_token']
  
  puts "3DS handled automatically"
  puts "Item state: #{item['state']}"
  
  # The payment_token will be provided if 3DS is required
  if payment_token
    puts "3DS verification required - use token: #{payment_token}"
  else
    puts "3DS verification not required - payment processed"
  end
end

Important Notes

  • The payment_token returned must be used to initialise the 3DS2 web component on the client side
  • After 3DS authentication is complete, the payment will automatically be processed
  • If 3DS verification fails or is abandoned, the payment will be cancelled
  • This endpoint supports 3D Secure 2.0, providing a better user experience than legacy 3DS 1.0
  • Always handle the response appropriately and provide clear instructions to users if 3DS verification is required

See also: For more information on implementing 3D Secure on the client side, refer to the Zai 3DS Integration Guide.

Authorize Payment

Authorize a payment without immediately capturing funds. This is useful for pre-authorization scenarios where you want to verify the card and hold funds before completing the transaction.

Required Parameters

  • account_id - The card account ID to authorize (Required)

Optional Parameters

  • cvv - Card CVV for additional verification
  • merchant_phone - Merchant contact phone number
# Authorize a payment
response = ZaiPayment.items.authorize_payment(
  "item-123",
  account_id: "card_account-456"    # Required
)

if response.success?
  item = response.data
  puts "Payment authorized for item: #{item['id']}"
  puts "State: #{item['state']}"
  puts "Payment State: #{item['payment_state']}"
end

Authorize with Optional Parameters

response = ZaiPayment.items.authorize_payment(
  "item-123",
  account_id: "card_account-456",  # Required
  cvv: "123",
  merchant_phone: "+61412345678"
)

if response.success?
  item = response.data
  puts "Payment authorized with CVV verification"
  puts "Item State: #{item['state']}"
  puts "Payment State: #{item['payment_state']}"
end

Note: After authorizing a payment, you'll need to capture it separately to complete the transaction. Authorized funds are typically held for 7 days before being automatically released.

Capture Payment

Capture a previously authorized payment to complete the transaction and transfer funds. This is the second step in a two-step payment process (authorize → capture).

Optional Parameters

  • amount - Amount to capture in cents (Optional). If not provided, captures the full authorized amount.
# Capture the full authorized amount
response = ZaiPayment.items.capture_payment("item-123")

if response.success?
  item = response.data
  puts "Payment captured for item: #{item['id']}"
  puts "State: #{item['state']}"
  puts "Payment State: #{item['payment_state']}"
end

Capture with Specific Amount (Partial Capture)

You can capture a partial amount of the authorized funds:

# Capture only $50 of a $100 authorized payment
response = ZaiPayment.items.capture_payment(
  "item-123",
  amount: 5000  # $50.00 in cents
)

if response.success?
  item = response.data
  puts "Partial payment captured: $#{item['amount'] / 100.0}"
  puts "Item State: #{item['state']}"
  puts "Payment State: #{item['payment_state']}"
end

Capture with Status Check

Check authorization status before attempting to capture:

# Check current status
status_response = ZaiPayment.items.show_status("item-123")

if status_response.success?
  payment_state = status_response.data['payment_state']
  
  # Only capture if payment is authorized
  if payment_state == 'authorized' || payment_state == 'payment_authorized'
    capture_response = ZaiPayment.items.capture_payment("item-123")
    
    if capture_response.success?
      puts "✓ Payment captured successfully"
    else
      puts "✗ Capture failed: #{capture_response.error_message}"
    end
  else
    puts "Payment cannot be captured - current state: #{payment_state}"
  end
end

Authorization and Capture Workflow

Complete example of the authorize → capture workflow:

# Step 1: Authorize the payment
auth_response = ZaiPayment.items.authorize_payment(
  "item-123",
  account_id: "card_account-456",
  cvv: "123"
)

if auth_response.success?
  puts "✓ Payment authorized"
  
  # Step 2: Verify authorization
  status = ZaiPayment.items.show_status("item-123")
  puts "Payment State: #{status.data['payment_state']}"
  
  # Step 3: Capture the payment (can be done immediately or later)
  capture_response = ZaiPayment.items.capture_payment("item-123")
  
  if capture_response.success?
    puts "✓ Payment captured and completed"
    puts "Final State: #{capture_response.data['payment_state']}"
  else
    puts "✗ Capture failed: #{capture_response.error_message}"
  end
end

Capture States and Conditions

Payments can be captured when in these states:

State Can Capture? Description
authorized ✓ Yes Payment authorized and ready to capture
payment_authorized ✓ Yes Payment authorized and ready to capture
pending ✗ No Payment not authorized yet
payment_pending ✗ No Payment processing, not authorized
completed ✗ No Already captured
payment_deposited ✗ No Already captured and deposited
cancelled ✗ No Authorization cancelled
refunded ✗ No Payment refunded

Important Notes:

  • Authorizations typically expire after 7 days if not captured
  • Partial captures are supported (capturing less than the authorized amount)
  • Once captured, the payment cannot be un-captured (but can be refunded)
  • Some card networks may support multiple partial captures, check with Zai support
  • The remaining authorized amount (if any) is automatically released after capture

Void Payment

Void a previously authorized payment to immediately release the held funds without capturing them. This is typically used when you need to cancel an authorized payment before capturing it.

# Void an authorized payment
response = ZaiPayment.items.void_payment("item-123")

if response.success?
  item = response.data
  puts "Payment voided successfully"
  puts "Item ID: #{item['id']}"
  puts "State: #{item['state']}"
  puts "Payment State: #{item['payment_state']}"
else
  puts "Void failed: #{response.error_message}"
end

Void with Status Check

Check authorization status before attempting to void:

# Check current status
status_response = ZaiPayment.items.show_status("item-123")

if status_response.success?
  payment_state = status_response.data['payment_state']
  
  # Only void if payment is authorized
  if payment_state == 'authorized' || payment_state == 'payment_authorized'
    void_response = ZaiPayment.items.void_payment("item-123")
    
    if void_response.success?
      puts "✓ Payment voided successfully"
    else
      puts "✗ Void failed: #{void_response.error_message}"
    end
  else
    puts "Payment cannot be voided - current state: #{payment_state}"
  end
end

Authorization Management Workflow

Complete example showing authorize → void workflow:

# Step 1: Authorize the payment
auth_response = ZaiPayment.items.authorize_payment(
  "item-123",
  account_id: "card_account-456",
  cvv: "123"
)

if auth_response.success?
  puts "✓ Payment authorized"
  
  # Step 2: Verify authorization
  status = ZaiPayment.items.show_status("item-123")
  puts "Payment State: #{status.data['payment_state']}"
  
  # Step 3: Void the payment (cancel the authorization)
  void_response = ZaiPayment.items.void_payment("item-123")
  
  if void_response.success?
    puts "✓ Payment voided - funds released"
    puts "Final State: #{void_response.data['payment_state']}"
  else
    puts "✗ Void failed: #{void_response.error_message}"
  end
end

Void vs Cancel vs Refund

Understanding when to use each operation:

Operation Use When Payment State Funds Status
Void Payment is authorized but not captured authorized, payment_authorized Funds held but not transferred
Cancel Item created but payment not yet authorized pending, payment_pending No funds involved
Refund Payment captured and completed completed, payment_deposited Funds already transferred

Key Differences:

  • Void: Releases authorized (held) funds immediately without any transfer
  • Cancel: Cancels the entire transaction before any payment authorization
  • Refund: Returns funds after they've been captured and transferred

Void States and Conditions

Payments can be voided when in these states:

State Can Void? Description
authorized ✓ Yes Payment authorized and ready to void
payment_authorized ✓ Yes Payment authorized and ready to void
pending ✗ No Payment not authorized yet, use cancel
payment_pending ✗ No Payment processing, use cancel
completed ✗ No Already captured, use refund
payment_deposited ✗ No Already captured, use refund
cancelled ✗ No Already cancelled
refunded ✗ No Already refunded
voided ✗ No Already voided

Important Notes:

  • Voiding a payment immediately releases the held funds to the cardholder
  • Once voided, the authorization cannot be reversed or captured
  • Void is instant - no settlement period required
  • No fees are charged for voiding an authorization
  • Voided authorizations do not appear on cardholder statements

Cancel Item

Cancel a pending item/payment. This operation is typically used to cancel an item before payment has been processed or completed.

response = ZaiPayment.items.cancel("item-123")

if response.success?
  item = response.data
  puts "Item cancelled successfully"
  puts "Item ID: #{item['id']}"
  puts "State: #{item['state']}"
  puts "Payment State: #{item['payment_state']}"
else
  puts "Cancel failed: #{response.error_message}"
end

Cancel with Status Check

Check item status before attempting to cancel:

# Check current status
status_response = ZaiPayment.items.show_status("item-123")

if status_response.success?
  current_state = status_response.data['state']
  
  # Only cancel if in a cancellable state
  if ['pending', 'payment_pending'].include?(current_state)
    cancel_response = ZaiPayment.items.cancel("item-123")
    
    if cancel_response.success?
      puts "✓ Item cancelled successfully"
    else
      puts "✗ Cancel failed: #{cancel_response.error_message}"
    end
  else
    puts "Item cannot be cancelled - current state: #{current_state}"
  end
end

Cancel States and Conditions

Items can typically be cancelled when in these states:

State Can Cancel? Description
pending ✓ Yes Item created but no payment initiated
payment_pending ✓ Yes Payment initiated but not yet processed
payment_processing Maybe Depends on payment processor
completed ✗ No Payment completed, must refund instead
payment_held Maybe May require admin approval
cancelled ✗ No Already cancelled
refunded ✗ No Already refunded

Note: If an item is already completed or funds have been disbursed, you cannot cancel it. In those cases, you may need to process a refund instead (contact Zai support for refund procedures).

Refund Item

Process a refund for a completed payment. This operation returns funds to the buyer and is typically used for customer returns, disputes, or service issues.

response = ZaiPayment.items.refund("item-123")

if response.success?
  item = response.data
  puts "Item refunded successfully"
  puts "Item ID: #{item['id']}"
  puts "State: #{item['state']}"
  puts "Payment State: #{item['payment_state']}"
else
  puts "Refund failed: #{response.error_message}"
end

Refund with Optional Parameters

You can optionally specify a refund amount (for partial refunds), a refund message, and the account to refund to:

response = ZaiPayment.items.refund(
  "item-123",
  refund_amount: 5000,        # Partial refund of $50.00 (in cents)
  refund_message: "Refund for damaged product",
  account_id: "account_789"   # Specific account to refund to
)

if response.success?
  item = response.data
  puts "✓ Partial refund processed: $#{item['refund_amount'] / 100.0}"
  puts "  State: #{item['state']}"
  puts "  Payment State: #{item['payment_state']}"
end

Refund with Status Check

Check item status before attempting to refund:

# Check current status
status_response = ZaiPayment.items.show_status("item-123")

if status_response.success?
  current_state = status_response.data['state']
  payment_state = status_response.data['payment_state']
  
  # Only refund if in a refundable state
  if ['completed', 'payment_deposited'].include?(payment_state)
    refund_response = ZaiPayment.items.refund("item-123")
    
    if refund_response.success?
      puts "✓ Item refunded successfully"
    else
      puts "✗ Refund failed: #{refund_response.error_message}"
    end
  else
    puts "Item cannot be refunded - payment state: #{payment_state}"
  end
end

Refund States and Conditions

Items can typically be refunded when in these states:

State Can Refund? Description
pending ✗ No Item not yet paid, cancel instead
payment_pending ✗ No Payment not completed, cancel instead
completed ✓ Yes Payment completed successfully
payment_deposited ✓ Yes Payment received and deposited
work_completed ✓ Yes Work completed, funds can be refunded
cancelled ✗ No Already cancelled
refunded ✗ No Already refunded
payment_held Maybe May require admin approval

Note: Full refunds return the entire item amount. Partial refunds return a specified amount less than the total. Multiple partial refunds may be possible depending on your Zai configuration.

Field Reference

Item Fields

Field Type Description Required
id String Unique item ID (auto-generated if not provided) Optional
name String Name/title of the item
amount Integer Amount in cents (e.g., 10000 = $100.00)
payment_type Integer Payment type (1-7, default: 2)
buyer_id String Buyer user ID
seller_id String Seller user ID
fee_ids Array Array of fee IDs to apply Optional
description String Detailed description Optional
currency String Currency code (e.g., 'AUD', 'USD') Optional
custom_descriptor String Custom text for bank statements Optional
buyer_url String URL for buyer to access transaction Optional
seller_url String URL for seller to access transaction Optional
tax_invoice Boolean Whether to generate a tax invoice Optional

Payment Types

When creating items, you can specify different payment types:

Type Description
1 Direct Debit
2 Credit Card (default)
3 Bank Transfer
4 Wallet
5 BPay
6 PayPal
7 Other

Example:

# Create item with bank transfer payment type
response = ZaiPayment.items.create(
  name: "Bank Transfer Payment",
  amount: 30000,
  payment_type: 3, # Bank Transfer
  buyer_id: "buyer-123",
  seller_id: "seller-456"
)

Item States

Items go through various states during their lifecycle:

  • pending - Item created but not yet paid
  • payment_pending - Payment in progress
  • payment_held - Payment held (e.g., for review)
  • payment_deposited - Payment received and deposited
  • work_completed - Work/delivery completed
  • completed - Transaction completed successfully
  • refunded - Transaction refunded
  • cancelled - Transaction cancelled

Check the item status using show_status method to track these state changes.

Error Handling

The Item resource will raise validation errors for:

  • Missing required fields
  • Invalid amount (must be positive integer in cents)
  • Invalid payment type (must be 1-7)
  • Invalid item ID format
  • Item not found
begin
  response = ZaiPayment.items.create(
    name: "Product",
    amount: -100, # Invalid: negative amount
    payment_type: 2,
    buyer_id: "buyer-123",
    seller_id: "seller-456"
  )
rescue ZaiPayment::Errors::ValidationError => e
  puts "Validation error: #{e.message}"
rescue ZaiPayment::Errors::NotFoundError => e
  puts "Item not found: #{e.message}"
rescue ZaiPayment::Errors::ApiError => e
  puts "API error: #{e.message}"
end

Best Practices

1. Use Meaningful Names and Descriptions

Always provide clear, descriptive names and descriptions for items. This helps with:

  • Transaction tracking
  • Customer support
  • Financial reconciliation
response = ZaiPayment.items.create(
  name: "Order #12345 - Premium Widget",
  description: "Premium widget with extended warranty - Customer: John Doe",
  amount: 29900,
  # ... other fields
)

2. Track Custom IDs

If you have your own order/transaction IDs, use the optional id field:

response = ZaiPayment.items.create(
  id: "order-#{your_order_id}",
  name: "Order #{your_order_id}",
  # ... other fields
)

3. Set Buyer and Seller URLs

Provide URLs so users can access transaction details on your platform:

response = ZaiPayment.items.create(
  buyer_url: "https://myapp.com/orders/#{order_id}",
  seller_url: "https://myapp.com/sales/#{order_id}",
  # ... other fields
)

4. Monitor Transaction Status

Regularly check item status to track payment and disbursement:

status_response = ZaiPayment.items.show_status(item_id)
puts "Payment: #{status_response.data['payment_state']}"
puts "Disbursement: #{status_response.data['disbursement_state']}"

5. Handle Fees Properly

If applying platform fees, create fee objects first and reference them:

# Assume you've created fees with IDs: "fee-platform", "fee-service"
response = ZaiPayment.items.create(
  name: "Product Purchase",
  amount: 50000,
  fee_ids: ["fee-platform", "fee-service"],
  # ... other fields
)

Response Structure

Successful Response

response.success? # => true
response.status   # => 200 or 201
response.data     # => Item object hash
response.meta     # => Pagination metadata (for list)

Item Object Example

{
  "id" => "item-abc123",
  "name" => "Product Purchase",
  "amount" => 10000,
  "payment_type" => 2,
  "buyer_id" => "buyer-123",
  "seller_id" => "seller-456",
  "description" => "Purchase of product XYZ",
  "currency" => "AUD",
  "state" => "pending",
  "payment_state" => "pending",
  "buyer_url" => "https://buyer.example.com",
  "seller_url" => "https://seller.example.com",
  "tax_invoice" => true,
  "created_at" => "2025-01-01T00:00:00Z",
  "updated_at" => "2025-01-01T00:00:00Z"
}

Complete Workflow Example

Here's a complete example of creating an item and tracking it through its lifecycle:

require 'zai_payment'

# Configure
ZaiPayment.configure do |config|
  config.client_id = ENV['ZAI_CLIENT_ID']
  config.client_secret = ENV['ZAI_CLIENT_SECRET']
  config.scope = ENV['ZAI_SCOPE']
  config.environment = :prelive
end

items = ZaiPayment.items

# 1. Create an item
create_response = items.create(
  name: "E-commerce Purchase - Order #12345",
  amount: 50000, # $500.00
  payment_type: 2, # Credit card
  buyer_id: "buyer-abc123",
  seller_id: "seller-xyz789",
  description: "Online store purchase - Premium product bundle",
  currency: "AUD",
  buyer_url: "https://store.example.com/orders/12345",
  seller_url: "https://seller.example.com/sales/12345",
  tax_invoice: true
)

if create_response.success?
  item_id = create_response.data['id']
  puts "✓ Item created: #{item_id}"
  
  # 2. Get item details
  show_response = items.show(item_id)
  puts "✓ Item: #{show_response.data['name']}"
  
  # 3. Get seller details
  seller_response = items.show_seller(item_id)
  puts "✓ Seller: #{seller_response.data['email']}"
  
  # 4. Get buyer details
  buyer_response = items.show_buyer(item_id)
  puts "✓ Buyer: #{buyer_response.data['email']}"
  
  # 5. Check fees
  fees_response = items.show_fees(item_id)
  if fees_response.success? && fees_response.data&.any?
    total_fees = fees_response.data.sum { |f| f['amount'] }
    puts "✓ Total fees: $#{total_fees / 100.0}"
  end
  
  # 6. Monitor status
  status_response = items.show_status(item_id)
  puts "✓ Payment state: #{status_response.data['payment_state']}"
  
  # 7. List transactions
  txn_response = items.list_transactions(item_id)
  puts "✓ Transactions: #{txn_response.data&.length || 0}"
  
  # 8. Update if needed
  update_response = items.update(
    item_id,
    description: "Updated: Order #12345 - Payment confirmed"
  )
  puts "✓ Item updated" if update_response.success?
else
  puts "✗ Error: #{create_response.error_message}"
end

Integration with Rails

In a Controller

class OrdersController < ApplicationController
  def create
    # Create users first (buyer and seller)
    # ... user creation code ...
    
    # Create item
    response = ZaiPayment.items.create(
      name: "Order ##{@order.id}",
      amount: (@order.total * 100).to_i, # Convert to cents
      payment_type: 2,
      buyer_id: @buyer_zai_id,
      seller_id: @seller_zai_id,
      description: @order.description,
      buyer_url: order_url(@order),
      seller_url: seller_order_url(@order),
      tax_invoice: @order.requires_tax_invoice?
    )
    
    if response.success?
      @order.update(zai_item_id: response.data['id'])
      redirect_to @order, notice: 'Order created successfully'
    else
      flash[:error] = "Payment error: #{response.error_message}"
      render :new
    end
  end
  
  def show
    # Get item status from Zai
    if @order.zai_item_id
      response = ZaiPayment.items.show_status(@order.zai_item_id)
      @payment_status = response.data if response.success?
    end
  end
end

In a Background Job

class CheckItemStatusJob < ApplicationJob
  def perform(order_id)
    order = Order.find(order_id)
    
    response = ZaiPayment.items.show_status(order.zai_item_id)
    
    if response.success?
      status = response.data
      
      order.update(
        payment_state: status['payment_state'],
        disbursement_state: status['disbursement_state']
      )
      
      # Send notifications based on state
      if status['payment_state'] == 'completed'
        OrderMailer.payment_completed(order).deliver_later
      end
    end
  end
end

Testing

The Item resource includes comprehensive test coverage. Run the tests with:

bundle exec rspec spec/zai_payment/resources/item_spec.rb

See Also

External Resources