Ruby SDK

Send invoices to Complyance from a Ruby application: install the gem, send a sample payload for mapping, then submit invoices and follow them. You need Ruby 2.6 or later and a sandbox API key.

Install

The gem is io-complyance-unify-sdk. The latest version is 3.0.12, a stable release.

Gemfile
gem "io-complyance-unify-sdk", "~> 3.0"

Then run bundle install.

In your code, load it with require "complyance_sdk".

Configure the SDK

Configure the SDK once, when your application starts.

Configure the SDK
require "complyance_sdk"

config = ComplyanceSDK::Config::SDKConfig.new(
  api_key: ENV.fetch("COMPLYANCE_API_KEY"),
  environment: ComplyanceSDK::Models::Environment::SANDBOX
)

ComplyanceSDK.configure(config)

SOURCE_NAME = "acme-erp"
SOURCE_VERSION = "1"
  • environment is Environment::SANDBOX for testing and Environment::PRODUCTION for live invoices. Use a sandbox key with sandbox and a production key with production.
  • SOURCE_NAME and SOURCE_VERSION name the system that sends the invoices, such as your ERP. Use the same pair for mapping and for invoicing, because Complyance uses it to find the mapping for your invoices.

Send a sample payload for mapping

Before you can submit invoices, Complyance needs to know how your fields match GETS, the Complyance standard invoice format. Send one invoice exactly as your system produces it, with the purpose set to mapping. Nothing is sent to a tax authority.

Send a sample payload for mapping
payload = {
  invoice_number: "INV-2026-0142",
  issue_date: "2026-09-22",
  currency: "AED",
  seller: { name: "Acme Trading LLC", trn: "100000000000003" },
  buyer: { name: "Gulf Retail LLC", trn: "100000000000011" },
  lines: [
    { description: "Office chairs", quantity: 4, unit_price: 250.0, vat_rate: 5 }
  ],
  total: 1050.0
}

document_type = ComplyanceSDK::Models::GetsDocumentType.builder
  .base(ComplyanceSDK::Models::BASE::TAX_INVOICE)
  .build

raw = ComplyanceSDK.push_to_unify_v2(
  SOURCE_NAME,
  SOURCE_VERSION,
  document_type,
  ComplyanceSDK::Models::Country::AE,
  ComplyanceSDK::Models::Operation::SINGLE,
  ComplyanceSDK::Models::Mode::DOCUMENTS,
  ComplyanceSDK::Models::Purpose::MAPPING,
  payload
)

result = ComplyanceSDK::Models::UnifyResponse.from_h(raw)
puts result.status

You should see success. The payload is now stored in your workspace.

Next, open the Integration engine in the Developer portal. In Payload Selection, choose the payload you sent, then map your fields to GETS and link the integration to your source.

Submit an invoice

Once the mapping is linked to your source, send invoices with the purpose set to invoicing. Use the same source name and version as for mapping.

The document type is a GETS document type: a base, such as BASE::TAX_INVOICE or BASE::CREDIT_NOTE, plus any modifiers that apply, such as MODIFIER::EXPORT. It decides which fields the invoice must contain.

Submit an invoice
document_type = ComplyanceSDK::Models::GetsDocumentType.builder
  .base(ComplyanceSDK::Models::BASE::TAX_INVOICE)
  .modifiers([ComplyanceSDK::Models::MODIFIER::B2B])
  .build

raw = ComplyanceSDK.push_to_unify_v2(
  SOURCE_NAME,
  SOURCE_VERSION,
  document_type,
  ComplyanceSDK::Models::Country::AE,
  ComplyanceSDK::Models::Operation::SINGLE,
  ComplyanceSDK::Models::Mode::DOCUMENTS,
  ComplyanceSDK::Models::Purpose::INVOICING,
  payload
)

result = ComplyanceSDK::Models::UnifyResponse.from_h(raw)

if result.success?
  document_id = result.data.dig("document", "documentId")
  puts "Accepted: #{document_id}"
else
  result.validation_errors.each { |error| puts error }
end
Invoice acceptedjson
{
  "status": "success",
  "data": {
    "document": {
      "documentId": "01K5EXAMPLE00000000000142"
    }
  }
}

success? is true only when the status is success and the response lists no validation errors. Keep the documentId to follow the invoice.

If the API cannot be reached, the SDK keeps the invoice and sends it again later. The status is then queued.

Run your invoices in sandbox, and through a testbed, before you switch environment to production.

Check a document’s status

Delivery to the tax authority continues after the response. Look up the document with its documentId.

Check a document's status
status = ComplyanceSDK.get_document_status("01K5EXAMPLE00000000000142")
data = status["data"]

puts data["state"]
puts data["isTerminal"]
Invoice accepted as compliantjson
{
  "success": true,
  "data": {
    "documentId": "01K5EXAMPLE00000000000142",
    "documentNumber": "INV-2026-0142",
    "country": "AE",
    "environment": "sandbox",
    "state": "final_valid",
    "isTerminal": true,
    "lastUpdatedAt": "2026-09-22T10:00:04.000Z"
  }
}

While isTerminal is false, the invoice is still being processed, so check again later. final_valid means it was accepted as compliant. To be told instead of asking, use webhooks.

Retrieve purchase invoices

Purchase invoices are the invoices your suppliers send you. To read them, the SDK also needs your workspace ID as client_id. If you do not have it, ask support@complyance.io.

Configure for purchase invoices
config = ComplyanceSDK::Config::SDKConfig.new(
  api_key: ENV.fetch("COMPLYANCE_API_KEY"),
  environment: ComplyanceSDK::Models::Environment::SANDBOX,
  client_id: ENV.fetch("COMPLYANCE_CLIENT_ID")
)

ComplyanceSDK.configure(config)

List the purchase invoices received in a date range. Each page holds up to limit invoices. While hasMore is true, ask for the next page with nextCursor, keeping the same dates and limit.

List purchase invoices
cursor = nil

loop do
  page = ComplyanceSDK.list_purchase_invoices(
    from: "2026-09-01",
    to: "2026-09-30",
    limit: 100,
    cursor: cursor
  )["data"]

  page["items"].each do |item|
    puts "#{item["invoiceNumber"]} from #{item["supplierName"]}"
  end

  break unless page["hasMore"]
  cursor = page["nextCursor"]
end

Get one purchase invoice by its documentId:

Get a purchase invoice
invoice = ComplyanceSDK.get_purchase_invoice("01JEXAMPLE0000000000000142")

puts invoice.document_number
puts invoice.state
puts invoice.is_terminal

Every field is described in List purchase invoices and Get a purchase invoice.

Handle errors

Every error the SDK raises is a ComplyanceSDK::Exceptions::SDKException, with a message and, where there is one, a suggestion.

Handle errors
begin
  raw = ComplyanceSDK.push_to_unify_v2(
    SOURCE_NAME, SOURCE_VERSION, document_type,
    ComplyanceSDK::Models::Country::AE,
    ComplyanceSDK::Models::Operation::SINGLE,
    ComplyanceSDK::Models::Mode::DOCUMENTS,
    ComplyanceSDK::Models::Purpose::INVOICING,
    payload
  )
rescue ComplyanceSDK::Exceptions::APIError => e
  puts "#{e.status_code}: #{e.message}"
  puts e.context[:response_body]
rescue ComplyanceSDK::Exceptions::SDKException => e
  puts e.message
  puts e.suggestion if e.suggestion
end
ErrorWhat it meansWhat to do
APIError with status_code 401The API key is missing, invalid, revoked or expired.Check COMPLYANCE_API_KEY, or create a new API key.
APIError with status_code 403The key belongs to a different environment from the one you configured.Use a sandbox key with Environment::SANDBOX and a production key with Environment::PRODUCTION.
ValidationError: Country not allowed for environmentThe SDK refused the country before sending anything.Use a country the SDK accepts for this environment, such as Country::AE.
ConfigurationError: SDK must be configured before making API callsComplyanceSDK.configure was not called, or the key or environment is missing.Configure the SDK before the first call.

NetworkError means the SDK could not reach Complyance. What each status code from the API means is in Errors.

Last updated