API Integration Guide

Quick Navigation
Approach

You can use Zaypay as a web service. This way your application can talk to Zaypay to provide your application with micropayment capabilities.

This communication will sometimes be initiated by your application (to request a payment to be setup, for instance) or by Zaypay (say, to give your application an update on a payment). All communication is done by sending http-requests back and forth. This document explains all methods the API can perform, and all the details involved.

But wait, before you dive in to understanding the details.. Note that you might not care about them at all! Before you build your own solution, you should really check out the next section. We might have done most of the work you need for you!

Tools, Plugins and Examples

Because using our ready-made classes, plugins and other tools to pull that API right into your web-environment you might never type a single URL. The tool does all the heavylifting.

Classes, gems and plugins allow you to abstract away the lower levels of communicating with Zaypay so you don't need to reinvent the wheel. Reay-made applications are fully functioning applications for PHP, Ruby on Rails (and very soon ASP and Android™ too) that give you an amazing headstart or perfect example te be inspired by and borrow heavily from. Please do use all of this to your advantage!

So let's list what we've got:

Ruby Gem Ruby
1.8.7 & 1.9.3
A gem wrapping the Zaypay API so you can focus on developing your solution without doing boring boilerplate stuff. Can be used with anything ruby, not limited to Ruby on Rails.
Full API example Rails App Ruby
1.8.7 & 1.9.3
This example Ruby on Rails application has Zaypay already integrated in. It uses full API integration. Us it as inspiration or as basis for your own application and save yourself a lot of development resources.
API + Payalogue example Rails App Ruby
1.8.7 & 1.9.3
This example Ruby on Rails application has Zaypay already integrated in. It uses both the API (for save and convenient payment creation) and the Payalogue (for compliant an convenient payment screens hosted by us). It's the best of both worlds! Feel free to use this as is or build off it.
Payalogue example Rails App Ruby
1.8.7 & 1.9.3
This example Ruby on Rails application has Zaypay already integrated in. It the Payalogue for compliant an convenient payment screens hosted by us. Again feel free to use this however you please.
PHP API class PHP
5.x
An OO class that wraps all the API-plumbing. Just call some methods on Zaypay-objects to do the dirty work for you.
PHP API with Payalogue example PHP
5.x
An example-script that uses (and includes) the API-class in combination with the Payalogue. It simply creates a payment with the API and sends you to the payment-screen (the Payalogue).
PHP API example PHP
5.x
An example-script that uses (and includes) the API-class, gives a pretty good idea of how this could be used.

But then again, that lifting isn't all that heavy. If you use a language or framework we don't have a class for, you can just do the low-level stuff yourself. We'll now discuss details about HTTP-Headers (to set and to expect), how authentication works and what URLs can be used to do what, all with short examples. We use command-line cURL in our example requests and display the results for the requests because it's easy to understand what's going on that way.

Authentication

Authentication is done by means of an "API-key". This randomly generated key is a property of the Price Setting you're using the API on. The key is unique for every Price Setting. Every Price Setting also has a unique ID. Both the Key and the ID are shown when you click 'Stats & Implementation' the Price Settings page. Should the key get compromised, edit that Price Setting to produce a new random one (and update your scripts accordingly). The Price Setting specific key should be added to the query-sting of any request you send. You can see these query-strings in all upcoming examples. By the way, anything sent over the wire in plain-text is insecure. We thus recommend you to always use https://secure.zaypay.com when using the API.

HTTP-Headers

When you send a request to the API, you want XML back from us. It is important to let the API know this is the requested format. You should do so by sending the appropriate header:

Accept: application/xml

To make that happen with command-line curl you use the -H option like this (the urls are discussed later):

curl -H "Accept: application/xml" "https://secure.zaypay.com/82.94.123.123/pay/1/locale_for_ip?key=..."

Not surprisingly, all responses requested that way will be XML, so containing the header:

Content-Type: application/xml

And responses starting with:

<?xml version="1.0" encoding="UTF-8"?>

If you're getting responses that don't start with that, or errors like these:

<h3>error</h3>
Payalogue id is unknown to us, maybe you didn't get it right?"

Means you didn't manage to correctly ask for xml and your request was interpreted as html. (For certain URLs that leads our system to think your requesting a payalogue-screen, hence the error).

If you don't have an easy way to specify the header (you should really be looking for a client-library that allows you to do this, as it's the only Right™ way to do it), you can fake your way though it be adding .xml at the end of the request. Like this:

curl "https://secure.zaypay.com/82.94.123.123/pay/1/locale_for_ip.xml?key=..."

Understanding XML Errors

All the examples following in the Reference of Methods will only show successful responses. But we don't expect nothing to ever go wrong: you can also get errors from the API. Errors will also have a http-status of 200, just like non-error responses. So for detecting errors look at the status-attribute of the response-node. Error-responses will always look like this:

<?xml version="1.0" encoding="UTF-8"?>
<response status="error">
  <error>A descriptive error message here</error>
</response>

You can get these self-explaining errors in the error-node:

error message
Not Found
Attempt to access a non-existent payment, an existing payment from the wrong country, or one that's not yours
That amount isn't supported by any payment method in any country for this Price Setting
No valid language and country could be deduced
Combination of PriceSetting-id and PriceSetting-key is unknown to us, maybe you didn't get it right?
The Price Setting doesn't provide this service in this specific country. You may have configured it not to, or it might not be available for the requested amount.
It is not supported to use dynamic amounts with a Price Setting that is in Full Control mode. Use one in (Super) Easy mode if you want to use dynamic amounts through the API.

Reference of Methods

Here follows a list of all API-methods, what they were meant to be used for and all their details.

By the way, note that we use an abbreviated API key, not to clutter up the examples too much. A real key is always 32 characters long, and only consists of numbers and letters.

API Method: locale_for_ip

You use this method to let Zaypay find out what country your customer is in, and what default language goes with that. You send Zaypay the ip-address of your customer Zaypay will return an XML-response with the customers 'locale'.

A locale is a combination of a language and a country such as 'en-GB', by the rules of rfc-3066. In this case the language is English and the country is the United Kingdom.

curl -H "Accept: application/xml" "https://secure.zaypay.com/82.94.123.123/pay/1/locale_for_ip?key=..."
Example Request and Response for locale_for_ip
URL https://secure.zaypay.com/your customers ip-address/pay/price setting id/locale_for_ip
mandatory
data
key=price setting key
example
curl -H "Accept: application/xml" "https://secure.zaypay.com/82.94.123.123/pay/1/locale_for_ip?key=..."
response
<?xml version="1.0" encoding="UTF-8"?> 
  <response status="success">
    <locale>en-NL</locale>
  </response>
Method Response Reference for locale_for_ip show inline examples
element / exampledescription
current-locale
This contains a locale, being a language followed by a country according to the IETF language tag standard.
language > code
This contains the language code according to the ISO 639-2 standard.
language > english-name
This contains the name of the language in English.
language > native-name
This contains the name of the language in the native tongue.
country > code
This contains the country code according to the ISO 3166-1-alpha-2 standard.
country > name
This contains the name of the country in English.

Having determined the locale of your customer will help you present the customer with a language/country-selection form that has the correct country and language pre-selected. For building that form you will need to know what languages and countries your Price Setting supports effectively. That's what the next API method is about.

API Method: list_locales

With this method, you can query your Price Setting to list languages and countries it supports (that is: countries you configured it to support, and languages we have translations for. Currently we offer translated instructions for the following languages: Indonesian, Bosnian, Danish, German, English, Spanish (Castellano), Spanish (Latin-American), French, Croatian, Italian, Dutch, Polish, Portuguese, Russian, Romanian, Serbian, Finnish, Swedish, Czech, Bulgarian and Hebrew.

The returned (XML-)list can be used to build a form with two dropdowns for your visitor to alter the selected local with. The Payalogue (example) does the same kind of thing.

Optionally an amount can be specified. This amount will be used to limit the returned Locales to the ones where that amount can be charged. Hold into account that the Price Margin that was set in the used Price Setting will be used to increase the amount if needed, possibly making certain Locales available where there are only payment methods available that can't exactly match the requested amount, but can match the requested amount increased up to the Price Margin percentage. If no amount is specified, the amount from the Price Setting is used. If you don't specify amounts over the API, you can keep it all in the Price Setting which could be convenient.

About amounts

All amounts must be specified in cents. You can optionally add a ISO 4217 currency code directly after the amount. These are valid amounts: 234, 123EUR, 1200ILS. If you specify an amount without currency code it is assumed to be in euros. If you want to charge the equivalent of € 1,23 you use 123 as amount. The API automatically converts to the local currency of the countries that don't have the currency that you used to define the amount.

Example Request and Response for list_locales
URL https://secure.zaypay.com/optional_amount/pay/price setting id/list_locales
mandatory
data
key=price setting key
optional
data
payalogue_id=payalogue id
example
with amount
curl -X GET -H "Accept: application/xml" "https://secure.zaypay.com/123/pay/1/list_locales?key=..."
example
with amount and currency
curl -X GET -H "Accept: application/xml" "https://secure.zaypay.com/123USD/pay/1/list_locales?key=..."
example
without amount
curl -X GET -H "Accept: application/xml" "https://secure.zaypay.com//pay/1/list_locales?key=..."
response
<?xml version="1.0" encoding="UTF-8"?>
<response status="success">
  <locale-info>
    <current-locale>nl-NL</current-locale>
  </locale-info>
  <languages>
    <language>
      <code>de</code>
      <english-name>German</english-name>
      <native-name>Deutsch</native-name>
    </language>
    <language>
      <code>en</code>
      <english-name>English</english-name>
      <native-name>English</native-name>
    </language>
    <language>
      <code>es</code>
      <english-name>Spanish (Castellano)</english-name>
      <native-name>Espa&#241;ol (Castellano)</native-name>
    </language>
    <language>
      <code>ls</code>
      <english-name>Spanish (Latin-American)</english-name>
      <native-name>Espa&#241;ol (Latinoam&#233;rica)</native-name>
    </language>
      ......
  </languages>
  <countries>
    <country>
      <code>NL</code>
      <name>Netherlands</name>
    </country>
    <country>
      <code>BE</code>
      <name>Belgium</name>
    </country>
    <country>
      <code>DE</code>
      <name>Germany</name>
    </country>
    <country>
      <code>ES</code>
      <name>Spain</name>
    </country>
  </countries>
</response>
Method Response Reference for list_locales show inline examples
element / exampledescription
current-locale
This contains a locale, being a language followed by a country according to the IETF language tag standard.
charged-amount
Shows the amount in local currency including local VAT your customer would be charged should he choose to pay using this payment method
eur-charged-amount
Shows the amount in EUR including local VAT your customer would be charged should he choose to pay using this payment method
payout
Shows your payout in EUR excluding any VAT that you would receive from zaypay should your customer choose to pay using this payment method
name
Textual identifier for the payment method. Can be any of phone, sms, phone_landline, phone_mobile
payment-method-id
Numeric representation of above. Can be any of 1, 2, 3, 4 in the same order as the above. Should be used in your call to create_payment to identify the payment method your customer selected.
very-short-instructions
Very short description in the language of the current locale you can show to your customer to inform them on what they can choose.
very-short-instructions-with-amount
Like the above but also including the amount.
formatted-amount
Same value as charged-amount but used in a string that formats the amount according to the rules of the language of your customer.

API Method: list_payment_methods

This method lets you fetch all payment methods for a certain locale, showing cost, payout and instruction for all available methods for the selected country. As with the list_locales-method you can specify an amount (unless you're using a full control Price Setting). In the response, we also send a various types of instructions in the selected language. You will probably find this very useful as we support a lot of languages.

Example Request and Response for list_payment_methods
URL https://secure.zaypay.com/optional_amount/locale/pay/price setting id/payments/new
mandatory
data
key=price setting key
optional
data
payalogue_id=payalogue id
example
with amount
curl -H "Accept: application/xml" "https://secure.zaypay.com/123/nl-NL/pay/1/payments/new?key=..."
example
without amount
curl -H "Accept: application/xml" "https://secure.zaypay.com//nl-NL/pay/1/payments/new?key=..."
response
<?xml version="1.0" encoding="UTF-8"?>
<response status="success">
  <locale-info>
    <current-locale>fr-NL</current-locale>
  </locale-info>
  <payment-methods>
    <payment-method>
      <charged-amount type="decimal">0.600000000</charged-amount>
      <eur-charged-amount type="decimal">0.6</eur-charged-amount>
      <payout type="decimal">0.420000000000000000</payout>
      <name>phone</name>
      <payment-method-id type="integer">1</payment-method-id>
      <very-short-instructions>payez par t&#233;l&#233;phone</very-short-instructions>
      <formatted-amount>&#8364; 0,60</formatted-amount>
      <very-short-instructions-with-amount>payez &#8364; 0,60 par t&#233;l&#233;phone</very-short-instructions-with-amount>
    </payment-method>
    <payment-method>
      <charged-amount type="decimal">0.600000000</charged-amount>
      <eur-charged-amount type="decimal">0.6</eur-charged-amount>
      <payout type="decimal">0.240000000000000000</payout>
      <name>sms</name>
      <payment-method-id type="integer">2</payment-method-id>
      <very-short-instructions>payez par sms</very-short-instructions>
      <formatted-amount>&#8364; 0,60</formatted-amount>
      <very-short-instructions-with-amount>payez &#8364; 0,60 par sms</very-short-instructions-with-amount>
    </payment-method>
  </payment-methods>
</response>
Method Response Reference for list_payment_methods show inline examples
element / exampledescription
current-locale
This contains a locale, being a language followed by a country according to the IETF language tag standard.
charged-amount
Shows the amount in local currency including local VAT your customer would be charged should he choose to pay using this payment method
eur-charged-amount
Shows the amount in EUR including local VAT your customer would be charged should he choose to pay using this payment method
payout
Shows your payout in EUR excluding any VAT that you would receive from zaypay should your customer choose to pay using this payment method
name
Textual identifier for the payment method. Can be any of phone, sms, phone_landline, phone_mobile
payment-method-id
Numeric representation of above. Can be any of 1, 2, 3, 4 in the same order as the above. Should be used in your call to create_payment to identify the payment method your customer selected.
very-short-instructions
Very short description in the language of the current locale you can show to your customer to inform them on what they can choose.
very-short-instructions-with-amount
Like the above but also including the amount.
formatted-amount
Same value as charged-amount but used in a string that formats the amount according to the rules of the language of your customer.

API Method: create_payment

Now you know where your customer is from, you've shown what payment methods are available and your customer has selected a payment method it's time to setup the payment. You use the create_payment method, and send along the API-key and the payment method your customer has selected. We return a full set of information about the prepared payment, with instructions and all kind of other useful data. All you need to do is inform the customer on how to proceed with the actual payment.

The XML returned by this call does not always contain the same nodes. This depends on the type of payment and the status the payment is in. Note for instance that the time and time-left variables in the xml are only applicable to payments with the payment method 'phone' and are based on a 'per minute' type. You could test for the existence of these time-variables and only display them when they are found. You might even use them to display a little growing bar as done in the Payalogue. Don't forget to use our various types of unbeatable (and automatically translated) instructions. They save you a lot of time and improve the experience the customer has.

Your own variables

One can think of a lot of cases where it would be very convenient to store some extra data of your own (some hash or id known in your application or database) in the payment in our database. This is possible. Just add extra variables to the query-string of the create_payment call, and they will be returned in status-requests to your report_url and be contained by payments in XML-form, such as returned by show_payment. Your extra variables are allowed to use at most 1k bytes, so we suggest you keep well under there.

Mix the API and the Payalogue (our payment screen)

Do you want to create the payment with our API, but not be bothered with building your own payment-screen? We can imagine! Mixing the API and the Payalogue comes to the rescue. First create the payment with the API, and specify the payalogue_id during the create-call. Then the payalogue_url pops up in the resulting XML. You can send the customer to this URL to make the payment and you get the best of both worlds (the API and the Payalogue). Just look at the tools plugins and examples at the top of this page. Choose one that uses both the API and Payalogue.

Not only does the payalogue_id work with the create payment API call, it also works with both the list_locales and list_payment_methods API calls. In some cases, there are payment options available in the Zaypay system that will only work in a Payalogue. When you specify the payalogue_id to these API calls, these payalogue-only payment methods will be taken into account.

If you use the API we strongly recommend using the Payalogue with it too as it eliminates a number of potential difficulties. You don't have to bother with compliance regarding disclaimers, support information and stuff like that, and you don't have to worry about the verification code step. Furthermore some payment methods to be added in the future might require you to use our Payalogue and won't be allowed to be used in your own payment screens. If you already use the Payalogue this way that won't cause you any extra work down the line.

The end-users IP-address

Another optional parameter to supply with the creation of a payment is the ipaddr parameter, which allows you to specify the IP-address of the end-user. When you fully integrate the Zaypay API, your customers will never make a direct connection to our service so we have no way of determining the IP-address of the end-user. Since this is useful information to have when investigating fraud-cases on behalf of an operator for example, we request that you supply the end-users IP-address manually when creating a payment.

Example Request and Response for create_payment
URL https://secure.zaypay.com/optional_amount/locale/pay/price setting id/payments/create
mandatory
data
key=price setting key
payment_method_id= payment method id
optional
data
payalogue_id=payalogue id
ipaddr= IP-address
example
with amount
curl -H "Accept: application/xml" "https://secure.zaypay.com/123/nl-NL/pay/1/payments/create?key=...&payment_method_id=1&ipaddr=192.168.1.5"
example
with amount and payalogue id
curl -H "Accept: application/xml" "https://secure.zaypay.com/123/nl-NL/pay/1/payments/create?key=...&payment_method_id=1&payalogue_id=2"
example
without amount
curl -H "Accept: application/xml" "https://secure.zaypay.com//nl-NL/pay/1/payments/create?key=...&payment_method_id=1"
example
without amount, with custom data
curl -H "Accept: application/xml" "https://secure.zaypay.com//nl-NL/pay/1/payments/create?key=...&payment_method_id=1&my_id=123"
response
<?xml version="1.0" encoding="UTF-8"?>
<response status="success">
  <payment>
    <created-at type="datetime">2011-02-23T14:02:35Z</created-at>
    <id type="integer">1343532</id>
    <locale>en-BE</locale>
    <paycode>677283</paycode>
    <payload-provided type="boolean">false</payload-provided>
    <ip-address>192.168.1.5</ip-address>
    <time type="integer">65</time>
    <total-amount type="decimal">1.23</total-amount>
    <currency>EUR</currency>
    <amount-euro type="float">1.23</amount-euro>
    <total-payout type="decimal">0.93167</total-payout>
    <time-left type="integer">65</time-left>
    <number>090336072</number>
    <formatted-number>0909-36072</formatted-number>
    <platform>phone</platform>
    <human-platform>phone</human-platform>
    <sub-platform>pay per minute</sub-platform>
    <cost-per-minute type="decimal">0.8</cost-per-minute>
    <partly-customer-phone-number>unknown</partly-customer-phone-number>
    <customer-phone-number-hash>unknown</customer-phone-number-hash>
    <status>prepared</status>
    <payment-method-id type="integer">1</payment-method-id>
    <payalogue-url>//nl-NL/pay/2/payments/1343532</payalogue-url>
  </payment>
  <your-variables>my_id=123&and=something_else</your-variables>
  <status-string>Your payment is prepared</status-string>
  <very-short-instructions>pay by phone</very-short-instructions>
  <very-short-instructions-with-amount>pay 1,23 &#8364; by phone</very-short-instructions-with-amount>
  <short-instructions>Call 0903-36072, dial in paycode 682541 and hold the line for 1 minute and 5 seconds to complete the payment</short-instructions>
  <long-instructions>Please call 0903-36072. You will be asked for a code. Dial in paycode 682541 using the keypad of your phone. You will have to hold the line for 1 minute and 5 seconds. Your browser will proceed and you can hangup the phone, having paid 1,23 &#8364;.</long-instructions>
  <disclaimer>If you are under 18, you confirm that you have parental permission and consent to incur these charges.</disclaimer>
</response>
Method Response Reference for create_payment show inline examples
element / exampledescription
created-at
Shows the moment the payment was created
id
The unique positive integer that identifies a payment
locale
This contains the locale (language-country) the payment was created in.
paycode
Contains a code that users need to either dial in their phones (these are 6 digit codes) or send in a text-message (4 digit ones), in order to start the payment.
payload-provided
Contains either true or false, depending on whether you used the mark_payload_provided method.
time
Is only present when the payment is of platform phone and sub_platform pay per minute and shows how long the customer should hold the line to have completed his payment
time-left
Shows time that is left for the customer to remain calling
mobile-surcharge-percentage
If applicable, shows mobile surcharge for a payment. This means that mobile callers will pay more than fixed-line callers. If this does not apply this XML-node is not present. When it is present, you should inform your user about the mobile surcharge.
status
Shows the status of the payment. Can be any of advanced, error, expired, gained, in_progress, paid, paid_out, paid_partially, paused, preparation_failed, prepared and settled. Look at the reporing section of this page to find out what every status actually means, and how we can send your HTTP-requests on every status change.
total-amount
The total amount the customer will be paying including VAT in the local currency.
amount-euro
As above, but in EUR.
total-payout
Shows your payout in EUR excluding any VAT for this payment.
number
Shows the unformatted number the customer should be calling or texting to.
formatted-number
Shows the same number, but this time in a nice-to-read format
platform
Shows the platform for this payment. Can be any of sms, phone, phone_landline, phone_mobile
human-platform
The platform with any underscores replaced by spaces
sub-platform
Only applicable for platform phone and shows the premium line type. Can be any of pay per call, pay per minute
cost-per-minute
Shows the premium rate in case of sub-platform being pay per minute
charged-amount
Shows the amount in local currency including local VAT your customer would be charged should he choose to pay using this payment method
eur-charged-amount
Shows the amount in EUR including local VAT your customer would be charged should he choose to pay using this payment method
payout
Shows your payout in EUR excluding any VAT that you would receive from zaypay should your customer choose to pay using this payment method
name
Textual identifier for the payment method. Can be any of phone, sms, phone_landline, phone_mobile
payment-method-id
Numeric representation of above. Can be any of 1, 2, 3, 4 in the same order as the above. Should be used in your call to create_payment to identify the payment method your customer selected.
your-variables
Returns your own variables you inserted into the payment while you created it. These are also communicated in the query-string of the report-requests.
messages-to-be-sent
Only for text-message payments, shows total number of messages the consumer will receive for this payment.
messages-left-to-be-sent
Only for text-message payments, shows number of message that zaypay still needs to be sent to the consumer.
partly-customer-phone-number
Shows part of the customers phone number. Beware that there are a number of different reasons this might be set to 'unknown'. Payments in the prepared status never have customer phone numbers, customers can choose not to send a caller-id when they make the call and some countries give us a fake number due to local legislation. Even if we have the number, we can't show you the last 3 digits.
customer-phone-number-hash
Salted Hashed value of the full customers phone number. This is always the same for the same number, so it allows you to identify payments are from the same phone, even though you don't know the full number
customer-mo-message
Only for text-message-payments, shows the full message as sent by the customer. The message always needs to start by a keyword (which here is PAY) and a paycode (this time its 1234). You can ask the customer to send more characters after the code. This won't disturb the payment process and gives you more freedom of how to use the system.
keyword
Only for text-message-payments, shows the keyword the message the customer must send needs to start with
verification-needed
Can be any of true, false, indicates that at this time the customer must be shown a form for providing the verification-code that was sent to the customer.
verification-tries-left
Can be any positive number between 0 and 4 and indicates how much tries the customer has left to get it right.
questionnaire > name
Only applicable if you are using the Payalogue, enabled the questionnaire and the customer has filled-in the name field
questionnaire > email
Only applicable if you are using the Payalogue, enabled the questionnaire and the customer has filled-in the email field
questionnaire > phone
Only applicable if you are using the Payalogue, enabled the questionnaire and the customer has filled-in the phone field
questionnaire > comments
Only applicable if you are using the Payalogue, enabled the questionnaire and the customer has filled-in the phone field
payalogue-url
Only for payments that have a Payalogue set and where it still is useful to send a customer to the payment. Allows mixing of the API and our hosted payment screens we call Payalogues. Very worth checking out as it can save you the time you would spend on creating a payment screen, just create the payment with the API and open an iframe for the customer with this URL where the customer can complete the payment.
very-short-instructions
Very short description in the language of the current locale you can show to your customer to inform them on what they can choose. This node is only shown when the payment is in a status that requires further action by the customer. Otherwise it is left out.
very-short-instructions-with-amount
Like the above but also including the amount. This node is only shown when the payment is in a status that requires further action by the customer. Otherwise it is left out.
short-instructions
Short translated instructions that you can use to inform the customer on what needs to be done to make the actual payment. This node is only shown when the payment is in a status that requires further action by the customer. Otherwise it is left out.
long-instructions
Long translated instructions that you can use to inform the customer on what needs to be done to make the actual payment. This node is only shown when the payment is in a status that requires further action by the customer. Otherwise it is left out.
disclaimer
Is not always part of the payment-node, but if it is, it contains a disclaimer that must be shown to the customer in an unobfuscated fashion. For USA payments the disclaimer can be quite large. You would want to test properly whether that fits in your layout.

Payment Status

That newly created payment (which isn't paid yet) has status "prepared". From now on every time the payment changes state to in_progress, paused, paid or error you will be notified of this fact by a request to your Report URL, that you specified in the used Price Setting. We don't send the actual payment-info to this url, just references to the payment.

Your script should then go and retrieve the payment through the show_payment API method. Fetching the payment-status is done with the show_payment API method. You obviously need to know the API-key of the Price Setting this payment was created through. If you use the integrated Payalogue, we'll send you the same thing, but with the payalogue_id, too. More about this can be found in the Payalogue Usage Guide.

This graph shows how payment status can lead to another.

Statuses

The following table lists all possible statuses that a payment can be in, with explanations.

status explanation
prepared The state every payment is in right after successful creation.
expired If your customer doesn't start the payment process within 4 hours the payment becomes expired. It will silently be cleaned up later. This is totally normal! To change ones mind is very human.
in_progress This means the payment process is going on right now. If for instance your customer needs to be on the phone for 50 seconds in order to complete the payment, during those 50 seconds the payment is in_progress. This state also occurs in text message based payments. There it means the customer has sent the message, we've sent (a) premium message(s) back to the customer and we're awaiting Delivery Reports to be sure the customer will be billed. For text-messages that phase should be short, but can be long under certain circumstances. Some of our suppliers retry internally if a first attempt fails. During this phase the payment is in_progress.
paused This state only occurs in phone based payments of the subtype 'pay per minute', and only when the customer hangs up too early or is disconnected somehow. Luckily, the customer can redial and only has to call for the remaining seconds. The instructions we provide indicate this clearly.
paid The customer has paid. You can give out the product. However very unlikely, it is possible the payment will be charged back. This can occur when customers don't pay their bills, or the payment was made with for instance a stolen phone and the operators or our suppliers contact us about some kind of fraud. Luckily in much more than 99.99% of the cases paid means paid.
gained This status means that the money came in for this payment and is eligible for payout. HTTP-Reporting of this status only occurs when you enable Extended Reporting in your account. There are some other conditions that must be met however. We need bank info for your account, you must have over €50,- withdrawable and there must not have been a payout less than 2 weeks ago. If you have more than €1000,- worth of gained payments you can always be paid out, the 2 week cool down doesn't apply in such cases. Depending on the payment method and the country it takes time for the gained status to be reached. Typically 45 days after the month ends the payment was made in. This is important to be aware of. This is caused by operators and sometimes our suppliers holding on to the money. We are constantly negotiating with our suppliers to keep this is low as possible.
paid_out This status occurs the moment we wire a sum of money into your backaccount that contains this payment. HTTP-Reporting of this status only occurs when you enable Extended Reporting in your account. Extended reporting can be very useful when automating financial processes on your end!
error This status means that there was a fatal problem with the payment such as a chargeback, a technical problem or a fraud case.

Disclaimer and Instructions

For some countries (like the USA, for example) a disclaimer tag will be set like you can see in the example above. You are required to display the disclaimer in the same view as where you put the instructions for your customers, without obfuscation. This means the disclaimer has to be fully visible and not be hiding behind a frame or link. Failure to do so will result in the suspension of your Zaypay account and you will be held accountable for any financial damage or loss as a result of this.

The same goes for the short-instructions or long-instructions. If the disclaimer tag is set, you must display the instructions as-is.

How we report to your Report URL

Here's an example of such a request to your Report URL as you could find it in your server-log, would your script be called 'report_script.php':

report_script.php?payment_id=1337&message=This%20payment%20changed%20state&price_setting_id=1&status=in_progress

As you can see you get the id of both the Payment involved and the Price Setting it sprang from. Your script should have the API-key for that Price Setting available. The payment status is also sent in this request, however this information should be used with caution. We advise to use the 'show_payment'-method to actively fetch the payment. (If you ensist, you can also use the status-variable directly. You'll have to check the request was coming from Zaypay. Expect requests coming from 91.216.137.31 through 91.216.137.34)

By default you get reporting for payments entering the following statuses: error, gained, in_progress, paid, paid_out, paused and prepared. However, since not everyone is interested in reports for statuses beyond paid, if you also want to get reports on payments going gained and paid_out, enable extended reporting in your account. This extended reporting allows for automating, bank reconciliation and other accounting processes that need to know when exactly money for a payment is wired to your bank account.

Your response to our reporting

It's important we get this message through to your report-script. That's why we require a *specific response* from your script that's living at the report_url. This response must be the 4-character string *ok* (yes, that is including the asterisks). If we don't get that, we'll continue to try to send that request until we do (or give up). You should use this feature to your advantage. If for instance your database is down, you could throw an error message in that response. That way we'll know to retry the request, and you'll still get it when your database comes up again.

API Method: show_payment

The show-payment method will for instance be used from the script that lives on the Report URL, you could also connect your backend to us this way, so you can fetch the payment-status from our systems whenever you like. To fetch all info about a payment use the following method (note the 3 slashes, they are needed as they delimit the unused spots for amount and locale):

Example Request and Response for show_payment
URL https://secure.zaypay.com///pay/price setting id/payments/payment id
mandatory
data
key=price setting key
example
curl -H "Accept: application/xml" "https://secure.zaypay.com///pay/1/payments/1234?key=..."
response
<?xml version="1.0" encoding="UTF-8"?>
<response status="success">
  <payment>
    <created-at type="datetime">2008-02-14T15:10:31Z</created-at>
    <id type="integer">1234</id>
    <locale>en-BE</locale>
    <paycode>682541</paycode>
    <payload-provided type="boolean">false</payload-provided>
    <time type="integer">65</time>
    <status>in_progress</status>
    <total-amount type="decimal">1.23</total-amount>
    <amount-euro type="float">1.23</amount-euro>
    <total-payout type="decimal">0.93167</total-payout>
    <time-left type="integer">33</time-left>
    <number>090336072</number>
    <formatted-number>0909-36072</formatted-number>
    <platform>phone</platform>
    <sub-platform>pay per minute</sub-platform>
    <cost-per-minute type="decimal">1.12</cost-per-minute>
    <partly-customer-phone-number>unknown</partly-customer-phone-number>
    <customer-phone-number-hash>unknown</customer-phone-number-hash>
    <verification-needed type="boolean">true</verification-needed>
    <verification-tries-left type="integer">3</verification-tries-left>
    <payment-method-id type="integer">1</payment-method-id>
    <payalogue-url>//en-BE/pay/2/payments/1234</payalogue-url>
    <questionnaire>
      <name>Myname</name>
      <email>name@adress.com</email>
      <phone>31636745237</phone>
      <comments>My test payment</comments>
    </questionnaire>
  </payment>
  <status-string>Your payment is in_progress</status-string>
  <very-short-instructions>pay by phone</very-short-instructions>
  <very-short-instructions-with-amount>pay 1,23 &#8364; by phone</very-short-instructions-with-amount>
  <short-instructions>Call 0903-36072, dial in paycode 682541 and hold the line for 1 minute and 5 seconds to complete the payment</short-instructions>
  <long-instructions>Please call 0903-36072. You will be asked for a code. Dial in paycode 682541 using the keypad of your phone. You will have to hold the line for 1 minute and 5 seconds. Your browser will proceed and you can hangup the phone, having paid 1,23 &#8364;.</long-instructions>
  <disclaimer>If you are under 18, you confirm that you have parental permission and consent to incur these charges.</disclaimer>
</response>

Method Response Reference for show_payment is identical to the one for create_payment

API Method: verification_code

In the above example, you'll notice a tag called verification-needed. When this tag is set to true, it is impossible for Zaypay to verify if a successful payment transaction has been performed, so it needs user input to verify this. The user input is in the form of a code that is sent with the last text message. You'll notice that the payment keeps its status of in_progress until the correct code has been supplied or when there are no more tries left, as is provided by the verification-tries-left tag.

To verify if a users' verification code is correct, you can call the verification_code API method. When this method returns the verification-needed as false or the status as paid, the verification code has been valid.

Example Request and Response for verification_code
URL https://secure.zaypay.com///pay/price setting id/payments/payment id/verification_code
mandatory
data
key=price setting key
verification_code= verification code
example
curl -H "Accept: application/xml" "https://secure.zaypay.com///pay/1/payments/1234/verification_code?key=...&verification_code=..."
response
<?xml version="1.0" encoding="UTF-8"?>
<response status="success">
  <payment>
    <created-at type="datetime">2008-02-14T15:10:31Z</created-at>
    <id type="integer">1234</id>
    <locale>en-BE</locale>
    <paycode>682541</paycode>
    <payload-provided type="boolean">false</payload-provided>
    <status>paid</status>
    <total-amount type="decimal">1.23</total-amount>
    <amount-euro type="float">1.23</amount-euro>
    <total-payout type="decimal">0.93167</total-payout>
    <number>3140</number>
    <formatted-number>3140</formatted-number>
    <platform>sms</platform>
    <cost-per-minute type="decimal">1.12</cost-per-minute>
    <partly-customer-phone-number>unknown</partly-customer-phone-number>
    <customer-phone-number-hash>unknown</customer-phone-number-hash>
    <verification-needed type="boolean">false</verification-needed>
    <payment-method-id type="integer">1</payment-method-id>
  </payment>

Method Response Reference for verification_code is identical to the one for create_payment

API Method: mark_payload_provided

When a payment is made some goodies must be delivered to the customer. You can use zaypay to register this has happened. This way you can conveniently decide whether a customer is trying to get a free ride without having to keep track of all payments in your own database. You get a 'payload-provided' flag in every xml describing a payment. When you're sure the product is delivered you can call the mark_payload_provided API method to store this fact with the payment in the zaypay database. Would you call the show API method on that payment you would see the product is already provided for the payment.

Example Request and Response for mark_payload_provided
URL https://secure.zaypay.com///pay/price setting id/payments/payment id/mark_payload_provided
mandatory
data
key=price setting key
example
curl -H "Accept: application/xml" "https://secure.zaypay.com///pay/1/payments/1234/mark_payload_provided?key=..."
response
<?xml version="1.0" encoding="UTF-8"?>
<response status="success">
  <payment>
    <created-at type="datetime">2008-02-19T13:40:00Z</created-at>
    <id type="integer">1234</id>
    <locale>en-NL</locale>
    <paycode>602983</paycode>
    <payload-provided type="boolean">true</payload-provided>
    <time type="integer">92</time>
    <status type="symbol">paid</status>
    <total-amount type="decimal">1.23</total-amount>
    <amount-euro type="float">1.23</amount-euro>
    <total-payout type="decimal">0.93533</total-payout>
    <time-left type="integer">0</time-left>
    <number>09091100400</number>
    <formatted-number>0909-1100400</formatted-number>
    <platform>phone</platform>
    <sub-platform>pay per minute</sub-platform>
    <cost-per-minute type="decimal">1.12</cost-per-minute>
    <platform>phone</platform>
  </payment>
</response>

Method Response Reference for mark_payload_provided is identical to the one for create_payment