NAV navbar
logo
responsebody

Merchant Integration Documentation

version v2
baseUri https://api.coowry.com/v2
protocols HTTPS

API Overview

The Coowry Transactional API is constructed as a RESTful service, and has been designed following these rules.

The API is resource oriented. Every resource offers a different view of the Coowry business data model. We rely on built-in HTTP features (authentication, verbs, etc.) that can be understood by off-the-shelf HTTP clients.

Request and Response Formats

         foo://example.com:8042/over/there?name=ferret#nose
         \_/   \______________/\_________/ \_________/ \__/
          |           |            |            |        |
       scheme     authority       path        query   fragment
          |   _____________________|__
         / \ /                        \
         urn:example:animal:ferret:nose

Source: http://tools.ietf.org/html/rfc3986

Monetary Values

All values must be in cents. If the currency does not have cents (eg. IDR), multiply the values by 100 before sending them to the API.

1.45 EUR -> 145
8 USD -> 800
10,000 IDR -> 1000000

Currencies

The Coowry API understands ISO 4217 currency codes.

Timestamps

Timestamps in Coowry are Unix timestamps, i.e. number of seconds between a particular date and the Unix Epoch (January 1st, 1970 at UTC).

MSISDNs

Phone numbers must follow standard MSISDN format, and be preceded by a +.

Authentication

Authentication is done via HTTP Basic Auth: Key and Secret.

All requests to the API must be done via HTTPS.

The Key authenticates the user and is used by the system to expose just the pieces of accesible information.

Timeouts

Calls to the /trades endpoints are advised to set a timeout of 30 seconds.

Versioning

Coowry uses Semantic Versioning in all its products. Versions follow the format X.Y.Z (X for major number, Y for minor number, and Z, for patch number). Bug fixes increment the patch version, backwards compatible changes increment the minor version, and backwards incompatible API changes increment the major version.

At this moment the major version operating is v2 and the current major version number can be found at https://api.coowry.com/v2.

API Errors

Error Object

{
  "status": <http status code>,
  "type": <error identifier>,
  "description": <human friendly description>,
  "arguments": <additional information>}
}

All errors returned by the Coowry API are JSON objects with the following fields

ParameterDescription
codeThe HTTP status code associated to this error
typeThe error type, unique to each error
descriptionHuman-friendly description of the error
argumentsAdditional information that completes the description

Coowry uses HTTP error codes to communicate the nature of the error. The errors returned by the API can be classified into three categories.

Your request is wrong (HTTP 400, 401, 403, 404).

You must check the request parameters and credentials before attempting another request.

Example Responses

HTTP/1.1 403 Forbidden
Content-Type: application/json
{
  "status": 403,
  "type": "forbidden",
  "description": "The request you made is not allowed",
  "arguments": {}}
}
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "status": 400,
  "type": "bad_request",
  "description": "Error in request parameters",
  "arguments": {
                 "non_valid":[],
                 "missing":["sender"],
                 "unexpected":[]
               }
}
codetypeDescription
400bad_requestThere is a problem with the parameters in your request. Look into fields description and arguments for more details.
401not_authorizedYour credentials are wrong
403forbiddenThe request you made is not allowed
404not_foundResource not found. Check the request URL

Coowry cannot perform the requested operation (HTTP 412).

These are errors unique to each process (payments, settlements, etc) and are to be expected during normal use of Coowry.

Example Responses

HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "sender_unidentified",
  "description":"Sender not identified",
  "arguments": {}
}
codetypeDescription
412_Errors unique to each process (payments, settlements, etc)

Server Errors (HTTP 500, 503)

There was an unexpected error on Coowry's side (HTTP codes 500 and 503). Try again later, and contact us if problem persists.

Example Responses

HTTP/1.1 503 Service Unavailable
Content-Type: application/json
{
  "status": 503,
  "type": "service_unavailable",
  "description":"We are improving our systems",
  "arguments": {}
}
codetypeDescription
500_Internal server error. Try again later, and contact us if problem persists
503service_unavailableThe Coowry API is temporarily unavailable (most likely maintenance is underway)

Payments Overview

Receiving payments through Coowry is a straightforward process and several options are available.

Trusted payments allow you to receive payments without having to wait for the customer's explicit authorization, but are only available to trusted merchants.

Besides trusted payments, two different flows are available, depending on your ability to receive the payment outcome asynchronously: synchronous payments and asynchronous payments.

Each flow offers different user experiences and a different coverage regarding the available telecom operators.

Trusted Payments

Trusted payments are a restricted feature that is only available for certain merchants. It allows you to receive payments from customers without having to wait for their explicit approval. Customers give their preapproval once and all subsequent payments are authorized directly.

This allows the payment process to have a seamless integration into your user experience.

Only subscribers of certain operators can be charged through this flow.

Synchronous Payments

If you do not wish to implement asynchronous callbacks, synchronous payments are your flow of choice.

The payment process consists of two synchronous calls to the API: one to create the trade and one to authorize it. In this case, the customer will confirm the payment by entering a security code sent to his phone.

While this is flow provides a simpler integration, it has some limitations: the user must have enough balance in his Coowry account before starting the payment.

Asynchronous Payments

If you can accept the payment outcome asynchronously, asynchronous payments provide you with a more flexible experience for the customer and a higher rate of completion.

The payment process consists of one synchronous call to create the trade, and an asynchronous callback from the API notifying the payment outcome. The customer will confirm the payment outside your page, through one of Coowry's channels (eg. SMS, app, web...).

With this flow, the user does not need to have enough balance in his Coowry account when starting the purchase. This provides more flexibility and a higher rate of completion.

Trusted Payments

Trusted payments allow you to receive payments from customers without having to wait for their explicit approval.

Your customers give their preapproval once, and all subsequent payments are executed directly.

This allows the payment process to have a seamless integration into your user experience.

Getting a customer's preapproval

Customers are redirected to Coowry to validate their phone and give their preapproval. The process is as follows,

Getting a customer's preapproval

  1. Make a POST request to the /preapprovals resource to start the preapproval process and get the redirection URL for the customer. Here is where you specify the return URLs to which the customer will be redirected after success or failure of the preapproval process.
  2. Redirect the customer to the redirection URL, where he will validate his phone number and complete the preapproval process.
  3. Once the preapproval process is complete the customer will be redirected to one of your URLs, specified during the first step.
  4. A notification of the outcome of the preapproval process will be sent to your callback URI.

Request

Making a POST to the /preapprovals resource will return a URL to which the customer can be redirected to start the preapproval process.

Example Request

HTTP/1.1 POST https://api.coowry.com/v2/preapprovals
Content-Type: application/json
{
        "success_url": "https://mycompany.com/foo",
        "failure_url": "https://mycompany.com/bar",
        "reference": "REF-123456789",
        "concept": "Preapproval for shop payments"
}

The following fields must be specified in the body of the request:

ParameterDescriptionNotes
success_urlThe URL to which the customer will be redirected after successfully completing the preapproval processThe protocol (eg. https:// must be included)
failure_urlThe URL to which the customer will be redirected if the preapproval process could not be completedThe protocol (eg. https:// must be included)
referenceOptional. Use it to store any information relevant to your internal processeg. your internal customer id
conceptOptional. Visible by the usereg. A small note to explain what the payment preapproval is for

The request must be authenticated by HTTP Basic Auth using your API key and secret. The body of the request must be encoded in application/json and the Content-Type header should be set accordingly.

Response: Success

Example Response

HTTP/1.1 200 OK
Content-Type: application/json
{
        "id": "RdeIQOaQEPUf",
        "redirect_url": "https://pay.coowry.com/RdeIQOaQEPUf",
}

If your request was successful, the API will return a JSON object with the following fields.

ParameterDescriptionNotes
idThe preapproval idUsed to order payments and check on the status of the preapproval
redirect_urlThe URL to which the customer must be redirected to complete the preapproval processPlease note that the URL can change between calls

Redirecting the customer to the redirection_url will start the preapproval process. You must store the preapproval id, as it is used to execute payments for this customer and check on the status of the preapproval.

Response: Failure

In case of failure, an API error is returned. A payment request can fail for several reasons:

Example Response (Check request parameters)

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "status": 400,
  "type": "bad_request",
  "description": "Error in request parameters",
  "arguments": {
                 "non_valid":[],
                 "missing":["success_url"],
                 "unexpected":[]
               }
}
codetypeDescription
400bad_requestThere is a problem with the parameters in your request. Look into fields description and arguments for more details.
401not_authorizedYour credentials are wrong
codetypeDescription
412merchant_not_trustedYou are not verified as a trusted merchant and cannot use the trusted payments flow

Executing a payment

To charge a customer, make a POST request to the /payments resource with the customer's preapproval id and the value to be charged.

Request

Example Request

HTTP/1.1 POST https://api.coowry.com/v2/payments
Content-Type: application/json
{
        "preapproval_id": "RdeIQOaQEPUf",
        "value": 812,
        "currency": "EUR",
        "concept": "Payment concept",
        "reference": "REF-123456789",
}

The following fields must be specified in the body of the request:

ParameterDescriptionNotes
preapproval_idThe customer's preapproval idYou must obtain a customer's preapproval before executing a trusted payment
valueThe value to be charged to the customerValue must be in cents (eg. 8.12 EUR is 812 cents)
currencyThe currency of the valueUse ISO 4217 currency codes
conceptThis is visible by the customer, and should be informative as to what he is being charged for
referenceOptional. Use it to store any data relevant to your internal billing processeg. your internal transaction ID

The request must be authenticated by HTTP Basic Auth using your API key and secret. The body of the request must be encoded in application/json and the Content-Type header should be set accordingly.

Response: Success

If the user can be charged through Coowry, the API replies with an HTTP 200 OK and a JSON object that represents the successful payment.

Example Response (Success)

HTTP/1.1 200 OK
Content-Type: application/json
{
        "id": "tr-la2js1mlrkrk",
        "status": "authorized",
        "preapproval_id": "RdeIQOaQEPUf",
        "value": 812,
        "currency": "EUR",
        "concept": "Payment concept",
        "reference": "REF-123456789"
}

Besides the fields you provided in the request, the returned object contains the following fields

ParameterDescriptionNotes
idThe payment's identification codeeg. tr-la2js1mlrkrk
statusStatus of the paymentWill always be authorized for trusted payments

Response: Failure

In case of failure, an API error is returned. A payment request can fail for several reasons:

Example Response (Check request parameters)

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "status": 400,
  "type": "bad_request",
  "description": "Error in request parameters",
  "arguments": {
                 "non_valid":[],
                 "missing":["value"],
                 "unexpected":[]
               }
}
codetypeDescription
400bad_requestThere is a problem with the parameters in your request. Look into fields description and arguments for more details.
400value_not_validThe value of the transaction is out of limits. Look into field arguments for limits in local currency
401not_authorizedYour credentials are wrong

Example Responses (Could not charge customer)

HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "preapproval_not_found",
  "description":"The given preapproval id does not exist",
  "arguments": {}
}
HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "net_not_active",
  "description":"Agent does not accept trades with the subscriber's network",
  "arguments": {
                 "opid": "op-00a6",
                 "operator": "Indosat"
               }
}
codetypeDescription
412merchant_not_trustedYou are not verified as a trusted merchant and therefore cannot use the trusted payments flow
412preapproval_not_activeThe preapproval is no longer active
412preapproval_not_foundThe preapproval id you provided does not exist
412sender_not_billedCoowry was unable to charge the user. This is usually due to an issue with the operator's billing systems. Try again and contact us problem persists
412sender_not_enough_balanceThe customer does not have enough balance to complete this paymentFor customers with a prepaid account
412net_not_activeThe merchant does not accept payments from subscribers of this network. This can happen if the preapproval id belongs to a customer of an operator from which you no longer accept payments
412sender_blacklistedThe customer is a suspect of fraudulent activity, and has been temporarily blacklisted

The error preapproval_not_active occurs when the customer has cancelled his preapproval. In rare cases, it could be that his phone number underwent a portability or the Terms of Agreement of his operator changed. In either case, the preapproval process should be relaunched for this customer.

Checking a customer's preapproval status

You can check on a customer's preapproval status by making a call to the /preapprovals resource. This is convenient since customers can cancel their preapproval of your payments at any given time.

Request

Example Request

HTTP/1.1 GET https://api.coowry.com/v2/preapprovals/RdeIQOaQEPUf

Make a GET request to /preapprovals/:id, where :id is the preapproval id. This will return the customer's preapproval status.

The body of the request must be left empty and the request must be authenticated by HTTP Basic Auth using your API key and secret.

Response: Success

Example Response

HTTP/1.1 200 OK
{
  "id": "RdeIQOaQEPUf",
  "reference": "REF-12345678",
  "active": "false",
  "concept": "Preapproval for shop payments"
}

If your request was successful, the API will return a JSON object with the following fields,

ParameterDescriptionNotes
idThe preapproval idSame as returned during the preapproval process
referenceProvided when creating the preapprovaleg. your internal customer id. null if not used
conceptProvided when creating the preapprovalVisible by the user, should be explanatory. null if not used
activetrue if the customer's preapproval is still active, false otherwiseIf false, attempting to execute a trusted payment with this customer will return an error

Response: Failure

Example Response (Check request parameters)

HTTP/1.1 404 Not Found
Content-Type: application/json
{
  "status": 404,
  "type": "not_found",
  "description": "Resource not found",
  "arguments": {}
}

In case of failure, an API error is returned. This request can fail if your credentials are wrong or you provided a preapproval id which does not exist.

codetypeDescription
401not_authorizedYour credentials are wrong
404not_foundResource not found. Check the request URL or make sure the provided id belongs to one of your customers

Cancelling a preapproval

You can use the preapprovals/:id/cancellation to cancel one of your customers preapprovals at any time. This is useful you want to allow customers to cancel their preapprovals directly from your service.

Please note that once cancelled, preapprovals cannot be reactivated. If you want to regian the customer's preapproval, you must repeat the process.

Request

Example Request

HTTP/1.1 POST
https://api.coowry.com/v2/preapprovals/GaDBJPHbVeZR/cancellation
Content-Type: application/json
{}

Making a POST to the /preapprovals/:id/cancellation resource, where :id is the preapproval id, will cancel the preapproval.

The body of the request must be left empty, and the request must be authenticated by HTTP Basic Auth using your API key and secret.

Response: Success

Example Response

HTTP/1.1 204 No Content
Content-Type: application/json

If your request was successful, the API will reply with HTTP Status 204 No Content.

Response: Failure

In case of failure, an API error is returned. A payment request can fail for several reasons:

Example Response (Check request parameters)

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{ 
  "status": "401",
  "type": "not_authorized",
  "description": "Unauthorized",
  "arguments": {}
}
HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{ 
  "status": "412",
  "type": "preapproval_not_active",
  "description": "The given preapproval is not active",
  "arguments": {
                 "id":"GaDBJPHbVeZR"
               }
}
codetypeDescription
401not_authorizedYour credentials are wrong
404not_foundResource not found. Check the request URL or make sure the provided id belongs to one of your customers
codetypeDescription
412preapproval_not_activeThe preapproval you are trying to cancel is not active

Synchronous Payments

This flow eliminates the need to implement asynchronous callbacks. Two synchronous calls are made to the API:

  1. The customer enters his MSISDN into the checkout page.
  2. You make a call to the API requesting a payment.
  3. If the customer can be charged through Coowry, the API returns an HTTP 200 OK and sends a security code to the user.
  4. The user accepts the Terms of Service and enters the security code into your page.
  5. You make a call to the API with the security code authorizing the payment.
  6. The trade is authorized.

Synchronous payments flow

The payment will expire after 1 hour and it will fail if a wrong security code is entered more than three times.

A customer can only have one active payment at a time.

Requesting a payment

To charge a customer you must create a trade requesting airtime from him. This is equivalent to making a POST request to /trades.

Request

Example Request

HTTP/1.1 POST https://api.coowry.com/v2/trades
Content-Type: application/json
{
        "sender": "+6212345678910",
        "receiver": "foo",
        "value": 500000,
        "currency": "IDR",
        "concept": "Subscription renewal",
        "reference": "REF-123456789",
}

The following fields must be specified in the body of the request:

ParameterDescriptionNotes
senderThe customer's MSISDNIn international format, eg. +34616839172 or +6212345678910
receiverYour API KeyProvided by Coowry
valueThe value to be charged to the customerValue must be in cents. For currencies that do not have cents (eg. IDR), multiply value by 100
currencyThe currency of said valueUse ISO 4217 currency codes
conceptThis will be seen by the customer, and should be informative as to what he is being charged for
referenceThis is for your use only. Use it to store any data relevant to your internal billing processeg. merchant's internal transaction ID

The body of the request must be encoded in application/json. The Content-Type header should be set accordingly.

Response: Success

If the user can be charged through Coowry, the API replies with an HTTP 200 OK and a JSON object that represents the created trade.

Example Response (Success)

HTTP/1.1 200 OK
Content-Type: application/json
{
        "id": "tr-la2js1mlrkrk",
        "reference": "REF-123456789",
        "status": "created",
        "created": 1440231774,
        "operator_terms":
          {
            "version": "0.9",
            "url": "http://example.com",
            "operator": "Orange"
          }
}

Among other fields, the trade object contains the following,

ParameterDescriptionNotes
idCoowry's trade identification codeeg. tr-la2js1mlrkrk
referenceMerchant's internal transaction IDSame as passed on the request
statusStatus of this transactionWill remain created until payment is authorized by the customer
createdCreation timestampIn epoch time
operator_termsJSON object containing the operator's terms of serviceIf not null, the user must accept them before confirming the purchase

Changes in the status of the trade (when it is authorized or fails) will be notified through a callback to the URI you have specified. More info on how to do this can be found in Section Receiving a Result.

Response: Failure

In case of failure, an API error is returned. A payment request can fail for several reasons:

Example Response (Check request parameters)

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "status": 400,
  "type": "bad_request",
  "description": "Error in request parameters",
  "arguments": {
                 "non_valid":[],
                 "missing":["sender"],
                 "unexpected":[]
               }
}
codetypeDescription
400bad_requestThere is a problem with the parameters in your request. Look into fields description and arguments for more details.
400value_not_validThe value of the transaction is out of limits. Valid values range from 0.01 USD to 10 USD (look into field arguments for limits in local currency)
401not_authorizedYour credentials are wrong
403forbiddenThe request you made is not allowed
404not_foundResource not found. Check the request URL

Example Responses (Could not charge customer)

HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "sender_unidentified",
  "description":"Sender not identified",
  "arguments": {}
}
HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "net_not_active",
  "description":"Agent does not accept trades with the subscriber's network",
  "arguments": {
                 "opid": "op-00a6",
                 "operator": "Indosat"
               }
}
HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "too_p2b_many_requests",
  "description": "Sender already has a pending purchase",
  "arguments": {
                 "open_requests": ["tr-6rc3alu7rqv6"]
               }
}
codetypeDescription
412sender_unidentifiedWe couldn't identify the customer's MSISDN. Make sure the MSISDN is correct. If problem persists, contact us
412sender_net_not_memberThe customer is a subscriber of a network which is not available through Coowry. Field arguments contains the mccmnc of the network
412sender_not_enough_balanceThe customer does not have enough balance in his Coowry account to complete this paymentCoowry will give instructions to the customer to charge his account
412net_not_activeThe merchant does not accept payments from subscribers of this network. Field arguments contains the name and id of the network. If you want to activate or deactivate payments for certain networks, contact us
412too_many_p2b_requestsCustomer already has a pending purchase. Authorize it or cancel it before attempting a new one. The trade id is returned in arguments
412sender_blacklistedThe customer is a suspect of fraudulent activity, and has been temporarily blacklisted

Authorizing the payment

After you succesfully request a payment from a user, Coowry will send a security code to the user via SMS. You must present the user with a form to enter this code (usually a 4-digit token) and the terms of service. Once the user enters the token, you must send it to the API to authorize the trade and complete the payment.

You must present the user with the terms of service. More info on how to do this here.

Request

The trade is authorized by making a POST to https://api.coowry.com/v2/trades/:trid/authorization where trid is the trade id returned after requesting the payment.

Example Request

HTTP/1.1 POST https://api.coowry.com/v2/trades/tr-la2js1mlrkrk/authorization
Content-Type: application/json
{
        "auth_token": "1234"
}

The following fields must be specified in the body of the request:

ParameterDescriptionNotes
auth_tokenAuthorization token4-digit security code entered by your customer

The body of the request must be encoded in application/json. The Content-Type header should be set accordingly.

Response: Success

If the security code was correct and the user has enough balance, the trade is authorized.

Example Response (Success)

HTTP/1.1 200 OK
Content-Type: application/json
{
        "id": "tr-la2js1mlrkrk",
        "status": "authorized",
        "sort": "p2b",
        "created": 1440231774

}

The API returns a JSON object containing the authorized trade.

ParameterDescriptionNotes
idCoowry's trade identification codeeg. tr-la2js1mlrkrk
statusStatus of this transactionValue will be authorized
sortSort of the transactionFor payments to merchants, sort is always p2b (peer to business)
createdCreation timestampIn epoch time

Response: Failure

In case of failure, an API error is returned. An attempt to authorize the trade can fail for several reasons,

Example Response (Check request parameters)

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "status": 400,
  "type": "bad_request",
  "description": "Error in request parameters",
  "arguments": {
                 "non_valid":[],
                 "missing":["sender"],
                 "unexpected":[]
               }
}
codetypeDescription
400bad_requestThere is a problem with the parameters in your request. Look into fields description and arguments for more details.
401not_authorizedYour credentials are wrong
403forbiddenThe request you made is not allowedRemember that trades ordered with delayed=true do not admit authorization by token
404not_foundResource not found. Check the request URL

Example Responses

HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "wrong_token",
  "description":"Wrong token",
  "arguments": {
                 "tries_left": 2
               }
}
HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "wrong_status",
  "description":"Trade is in the wrong status",
  "arguments": {
                 "status": "authorized"
               }
}
codetypeDescription
412sender_not_billedCoowry was unable to charge the user. This is usually due to an issue with the operator's billing systems
412sender_not_enough_balanceThe customer does not have enough balance in his Coowry account to complete this paymentCoowry will give instructions to the customer to charge his account
412wrong_tokenThe authorization token is wrongField arguments contains the number of remaining attempts
412too_many_auth_attemptsToken was wrong and the maximum number of authorization attemtps has been reached. The trade is failed
412wrong_statusThe trade has already been authorized or has failed

Cancelling a payment

A payment can be cancelled before it is authorized. This is a convenient feature and you should give the customer the possibility to cancel the payment.

Request

Example Request

HTTP/1.1 POST https://api.coowry.com/v2/trades/tr-la2js1mlrkrk/cancellation
Content-Type: application/json
{}

The trade is cancelled by making a POST request to https://api.coowry.com/v2/trades/:trid/cancellation, where trid is the trade id returned after requesting the payment.

The body of the request must be left empty and be encoded in application/json. The Content-Type header should be set accordingly.

Response: Success

The API returns a JSON object containing the cancelled trade.

Example Response (Success)

HTTP/1.1 200 OK
Content-Type: application/json
{
        "id": "tr-la2js1mlrkrk",
        "status": "failed",
        "sort": "p2b",
        "created": 1440231774

}
ParameterDescriptionNotes
idCoowry's trade identification codeeg. tr-la2js1mlrkrk
statusStatus of this transactionValue will be failed after cancellation
sortSort of the transactionFor payments to merchants, sort is always p2b (peer to business)
createdCreation timestampIn epoch time

Response: Failure

In case of failure, an API error is returned. An attempt to cancel a trade can fail for several reasons.

Example Response (Check request parameters)

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "status": 401,
  "type":" not_authorized",
  "description": "Unauthorized",
  "arguments": {}
}
codetypeDescription
400bad_requestThere is a problem with the parameters in your request. Look into fields description and arguments for more details.
401not_authorizedYour credentials are wrong
403forbiddenThe request you made is not allowedThis probably means the trid you specified references a different trade
404not_foundResource not found. Check the request URL

Example Responses

HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "wrong_status",
  "description":"Trade is in the wrong status",
  "arguments": {
                 "status": "authorized"
               }
}
codetypeDescription
412wrong_statusThe trade has already been authorized or has failed

Resending the authorization SMS

You can force the resend of an authorization SMS, which contains the security code to authorize a trade. This is useful in cases when the SMS is not delivered or the customer can’t find it.

The authorization SMS can be resent a maximum of three times. Please note that the the security code changes every time the SMS is resent.

Request

Example Request

HTTP/1.1 POST https://api.coowry.com/v2/trades/tr-la2js1mlrkrk/tokens
Content-Type: application/json
{}

The authorization SMS is resent by making a POST request to https://api.coowry.com/v2/trades/:trid/tokens, where trid is the trade id returned after requesting the payment.

The body of the request must be left empty and be encoded in application/json. The Content-Type header should be set accordingly.

Response: Success

The API returns an HTTP 204 No Content and an empty body.

Example Response (Success)

HTTP/1.1 204 No Content
Content-Type: application/json
{}

Response: Failure

In case of failure, an API error is returned. An attempt to resend the authorization SMS can fail for several reasons.

Example Response (Check request parameters)

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "status": 401,
  "type":" not_authorized",
  "description": "Unauthorized",
  "arguments": {}
}
codetypeDescription
400bad_requestThere is a problem with the parameters in your request. Look into fields description and arguments for more details.
401not_authorizedYour credentials are wrong
403forbiddenThe request you made is not allowedRemember that trades ordered with delayed=true do not admit authorization by token
404not_foundResource not found. Check the request URL

Example Responses

HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "wrong_status",
  "description":"Trade is in the wrong status",
  "arguments": {
                 "status": "authorized"
               }
}
codetypeDescription
412wrong_statusThe trade has already been authorized or has failed

Terms of Service

Only Coowry's Terms of Service

By authorizing the payment you are accepting Coowry's Terms of Service

"operator_terms": null

With Operator's Terms of Service

By authorizing the payment you are accepting Coowry's Terms of Service and Indosat's Terms of Service

"operator_terms":
  {
    "url": "http://example.com",
    "operator": "Indosat",
    "version": "1.2"
  }

Before authorizing the payment, the user must accept Coowry's Terms of Service and, if necessary, its operator's Terms of Service.

The acceptance can be implicit, ie. the user accepts the terms by entering the security code and authorizing the payment. The wording must be something similar to (in the local language),

By authorizing the payment you are accepting Coowry's Terms of Service

or, if the operator's Terms of Service are present,

By authorizing the payment you are accepting Coowry's Terms of Service and Indosat's Terms of Service

The URL to Coowry's Terms of Service is https://www.coowry.com/terms.

The URL to the operator's Terms of Service is can be found inside the field operator_terms returned when requesting a payment.

If this field is null, the user only needs to accept Coowry's terms of service. If not, this field is a JSON object with the following fields,

Asynchronous Payments

This uses one synchronous call to the API to order the payment and a callback to receive the outcome,

  1. The customer enters his MSISDN into the checkout page.
  2. You make a call to the API requesting a payment.
  3. If the customer can be charged through Coowry, the API returns an HTTP 200 OK.
  4. The user follows instructions sent to his mobile to complete the trade.
  5. You receive a callback from the Coowry API with the payment outcome (either authorized or failed).

Asynchronous payment flow

The payment will expire after 1 hour and a customer can only have one active payment at a time. You will be notified through the callback when the payment expires.

Requesting a payment asynchronously

To charge a customer you must create a trade requesting airtime from him. This is equivalent to making a POST request to /trades.

Request

Example Request

HTTP/1.1 POST https://api.coowry.com/v2/trades
Content-Type: application/json
{
        "sender": "+6212345678910",
        "receiver": "foo",
        "value": 500000,
        "currency": "IDR",
        "concept": "Subscription renewal",
        "reference": "REF-123456789",
        "delayed": true
}

The following fields must be specified in the body of the request:

ParameterDescriptionNotes
senderThe customer's MSISDNIn international format, eg. +34616839172 or +6212345678910
receiverYour API KeyProvided by Coowry
valueThe value to be charged to the customerValue must be in cents. For currencies that do not have cents (eg. IDR), multiply value by 100
currencyThe currency of said valueUse ISO 4217 currency codes
conceptThis will be seen by the customer, and should be informative as to what he is being charged for
referenceThis is for your use only. Use it to store any data relevant to your internal billing processeg. merchant's internal transaction ID
delayedMust be set to true to indicate that you will be notified of the payment outcome via callbackSetting your Callback URI

The body of the request must be encoded in application/json. The Content-Type header should be set accordingly.

Response: Success

If the user can be charged through Coowry, the API replies with an HTTP 200 OK and a JSON object that represents the created trade.

Example Response (Success)

HTTP/1.1 200 OK
Content-Type: application/json
{
        "id": "tr-la2js1mlrkrk",
        "reference": "REF-123456789",
        "status": "created",
        "created": 1440231774

}

Among other fields, the trade object contains the following,

ParameterDescriptionNotes
idCoowry's trade identification codeeg. tr-la2js1mlrkrk
referenceMerchant's internal transaction IDSame as passed on the request
statusStatus of this transactionWill remain created until payment is authorized by the customer
createdCreation timestampIn epoch time

The customer must now authorize the purchase. Changes in the status of the trade (when it is authorized or fails) will be notified through a callback to the URI you have specified. More info on how to do this can be found in section Receiving a Result.

Response: Failure

In case of failure, an API error is returned. A payment request can fail for several reasons:

Example Response (Check request parameters)

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "status": 400,
  "type": "bad_request",
  "description": "Error in request parameters",
  "arguments": {
                 "non_valid":[],
                 "missing":["sender"],
                 "unexpected":[]
               }
}
codetypeDescription
400bad_requestThere is a problem with the parameters in your request. Look into fields description and arguments for more details.
400value_not_validThe value of the transaction is out of limits. Valid values range from 0.01 USD to 10 USD (look into field arguments for limits in local currency)
401not_authorizedYour credentials are wrong
403forbiddenThe request you made is not allowed
404not_foundResource not found. Check the request URL

Example Responses (Could not charge customer)

HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "sender_unidentified",
  "description":"Sender not identified",
  "arguments": {}
}
HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "net_not_active",
  "description":"Agent does not accept trades with the subscriber's network",
  "arguments": {
                 "opid": "op-00a6",
                 "operator": "Indosat"
               }
}
HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "too_p2b_many_requests",
  "description": "Sender already has a pending purchase",
  "arguments": {
                 "open_requests": ["tr-6rc3alu7rqv6"]
               }
}
codetypeDescription
412sender_unidentifiedWe couldn't identify the customer's MSISDN. Make sure the MSISDN is correct. If problem persists, contact us
412sender_net_not_memberThe customer is a subscriber of a network which is not available through Coowry. Field arguments contains the mccmnc of the network
412callback_not_definedYou ordered the trade with delayed=true but you haven't set a notification callback.
412net_not_activeThe merchant does not accept payments from subscribers of this network. Field arguments contains the name and id of the network. If you want to activate or deactivate payments for certain networks, contact us
412too_many_p2b_requestsCustomer already has a pending purchase. Authorize it or cancel it before attempting a new one. The trade id is returned in arguments
412sender_not_enough_balanceThe customer does not have enough balance in his Coowry account to complete this paymentCoowry will give instructions to the customer to charge his account
412sender_blacklistedThe customer is a suspect of fraudulent activity, and has been temporarily blacklisted

Receiving the result

Coowry will make a callback to your callback URI when a payment you have requested is authorized by the customer or it fails. A POST request will be made to the URI that you have specified, informing you of the event.

Callback example

You will receive the following request at your callback URI

HTTP/1.1 POST
Content-Type: application/json
{
  "event": "trade_status_changed",
  "signature": "9e4b6b9143076547f0b8331514a6260bc428f777",
  "payload": {
               "id": "tr-la2js1mlrkrk",
               "reference": "REF-123456789",
               "status": "authorized",
               "failure": null
             }
}

The request follows Coowry's callback request format

ParameterDescriptionNotes
eventThe event that triggered this callbackIn this case, trade_status_changed
payloadThe payload of the callbackIn this case, information on the trade that was authorized or failed
signatureSignature used to verify that the call originated from Coowry's serversFor more info on how to calculate the signature, see section Calculating the Signature

In this case, the payload will be a JSON object with the following fields,

ParameterDescriptionNotes
idCoowry's trade identification codeeg. tr-la2js1mlrkrk
referenceMerchant transaction Id.This will be the same as the field reference you provided during the payment request
statusStatus of the paymentFor callbacks this will always be authorized or failed
failureFailure reason (if status=failed)If the transaction failed this field contains the reason for the failure, null otherwise

The field status represents the status of the transaction. If status=failed, the reason for failure can be one of the following,

FailureReason
sender_not_billedAn error ocurred when trying to charge the customer's phone. Try again and contact us problem persists
sender_not_enough_balanceThe user did not have enough balance in his prepaid account to complete the transaction
cancelledThe user cancelled the transaction
token_timeoutThe transaction expired
bill_errorCould not charge the user's account. Try again and contact us if problem persists

The user should be informed if the transaction failed before it was completed.

Your reply should be one of the following

HTTP/1.1 200 OK
EMPTY BODY

HTTP/1.1 204 No Content
EMPTY BODY

If the response is something else, Coowry will reattempt the callback three times. If still unsucesfull, you will by notified by another channel (eg. an email from the Coowry team).

Callback alternative: Polling for the result

If you prefer, you can poll for the result synchronously instead of waiting for a callback. You can retrieve the status of a transaction by performing a GET over the /trades resource.

Request

Example Request

HTTP/1.1 GET https://api.coowry.com/v2/trades/tr-la2js1mlrkrk
Content-Type: application/json

To check the status of a transaction, simply make a GET request to /trades/:id, where :id is the transaction Id returned when ordering the payment. The body must be left empty.

Response

Example Response

{
  "id": "tr-la2js1mlrkrk",
  "reference": "REF-123456789",
  "status": "authorized",
  "failure": null
}

The API will return a JSON object representing the transaction, which contains the following fields (same as posted to your callback URI),

ParameterDescriptionNotes
idCoowry's trade identification codeeg. tr-la2js1mlrkrk
referenceMerchant transaction Id.This will be the same as the field reference you provided during the payment request
statusStatus of the paymentFor callbacks this will always be authorized or failed
failureFailure reason (if status=failed)If the transaction failed this field contains the reason for the failure, null otherwise

The field status represents the status of the transaction. If status=failed, the reason for failure can be one of the following,

FailureReason
sender_not_billedAn error ocurred when trying to charge the customer's phone. Try again and contact us problem persists
sender_not_enough_balanceThe user did not have enough balance in his prepaid account to complete the transaction
cancelledThe user cancelled the transaction
token_timeoutThe transaction expired

The user should be informed if the transaction failed before it was completed.

Cancelling a payment

Asynchronous payments can also be cancelled before they are authorized. The behaviour is the same as in synchronous payments, as described in Cancelling a Payment.

This is a convenient feature and you should give the customer the possibility to cancel the payment.

Settlements

Making an airtime settlement to a customer is a straightforward process that consists of a single call to the API.

However, some considerations must be taken when selecting the value of the settlement.

Retrieving a customer's topup values

With the exception of some operators in Spain, most operators don't offer a flexible value range for topups, but a fixed set of values instead.

While you can transfer any value to your customers, in some cases it might be convenient to transfer exactly the amount available for topup, as their phone will be topped up automatically.

To know what the topup values are for a customer, make a GET request over /numbers/:msisdn, where :msisdn is the customer's phone number.

Request

Example Request

HTTP/1.1 GET https://api.coowry.com/v2/numbers/+628131234567
Content-Type: application/json

A GET request over /numbers/:msisdn will return the available topup values for the phone number :msisdn, along with some other information.

The body must be left empty and the MSISDN must be in international format. As with all other calls to the API, the request must be authenticated by HTTP Basic Auth using your API key and secret.

Response: Success

Example Response (Prepaid number)

{
    "topup": {
        "values": "enum",
        "enum": [
            {
                "value": 500000,
                "currency": "IDR"
            },
            {
                "value": 1000000,
                "currency": "IDR"
            },
            .
            .
            .
            {
                "value": 2000000,
                "currency": "IDR"
            }
        ]
    },
    "prepaid": null,
    "country": "ID",
    "operator_name": "Telkomsel",
    "operator_avatar": "https://imgcdn.coowry.com/op-0120.png"
}

Example Response (Postpaid number)

{
    "topup": null,
    "prepaid": false,
    "country": "ID",
    "operator_name": "Telkomsel",
    "operator_avatar": "https://imgcdn.coowry.com/op-0120.png",
}

If the number is a valid MSISDN, the API will return a JSON object with the following fields,

ParameterDescriptionNotes
topupA JSON object with the customer's topup informationThe format of the array can be found below
prepaidfalse if the customer is postpaid, true if it is prepaid and null if Coowry could not retrieve this informationWhen the customer is postpaid (prepaid=false) there will be no available values for topup
countryThe customer's country (eg. ID)In ISO 3166-1 format
operator_nameThe name of the customer's operatoreg. Indosat, Telkomsel, Movistar...
operator_avatarThe operator's logoReferenced by a link to the image

The field topup will be null if no values are available for the given number (eg. the number is postpaid). Otherwise, it will contain a JSON object with the following fields,

ParameterDescriptionNotes
valuesIndicates the type of values available (either enum or flex)Always enum for customers from Indonesia, where only fixed topup values are available
enumAn array of JSON objects containing the available topup valuesEach JSON object contains two fields (value and currency)

The field enum contains an array of JSON objects with the following fields,

A customer's phone will be automatically topped up if the settlement is made with one of these values.

Response: Failure

Example response (Number not valid)

HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
    "status": 401,
    "type": "not_authorized",
    "description": "Unauthorized",
    "arguments": {}
}

If the number is not valid or cannot be identified, the following API error is returned

codetypeDescription
412sender_unidentifiedWe couldn't identify the customer's MSISDN. Make sure the MSISDN is correct. If problem persists, contact us

Making a settlement

To make a settlement you must create a trade sending airtime to the customer.

This is equivalent to making a POST request to /trades.

Request

Example Request

HTTP/1.1 POST https://api.coowry.com/v2/trades
Content-Type: application/json
{
        "sender": "foo",
        "receiver": "+6212345678910",
        "value": 500000,
        "currency": "IDR",
        "concept": "Monthly settlement",
        "reference": "REF-123456789",

}

The following fields must be specified in the body of the request:

ParameterDescriptionNotes
senderYour API KeyProvided by Coowry
receiverThe customer's MSISDNIn international format, eg. +34616839172 or +6212345678910
valueThe value to be sent to the customerValue must be in cents. For currencies that do not have cents (eg. IDR), multiply value by 100
currencyThe currency of said valueUse ISO 4217 currency codes
conceptThis will be seen by the customer, and should be informative
referenceThis is for your use only. Use it to store any data relevant to your internal settlement processeg. merchant's internal transaction ID

The body of the request must be encoded in application/json. The Content-Type header should be set accordingly.

Response: Success

The API responds with an HTTP 200 OK and the airtime has been transfered to your customer. The trade's status is authorized and the settlement is complete.

Example Response (Success)

HTTP/1.1 200 OK
Content-Type: application/json
{
        "id": "tr-la2js1mlrkrk",
        "reference": "REF-123456789",
        "status": "authorized",
        "created": 1440231774

}

The API returns a JSON object with the following fields (besides the ones you defined in the request).

ParameterDescriptionNotes
idCoowry's trade identification codeeg. tr-la2js1mlrkrk
referenceMerchant's internal transaction IDSame as passed on the request
statusStatus of this transactionAlways authorized for settlements if the request was made through the API
createdCreation timestampIn epoch time

Response: Failure

In case of failure, an API error is returned. A settlement request can fail for several reasons:

Example Response (Check request parameters)

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "status": 400,
  "type": "bad_request",
  "description": "Error in request parameters",
  "arguments": {
                 "non_valid":[],
                 "missing":["sender"],
                 "unexpected":[]
               }
}
codetypeDescription
400bad_requestThere is a problem with the parameters in your request. Look into fields description and arguments for more details.
400value_not_validThe value of the transaction is out of limits. Valid values range from 0.01 USD to 10 USD (look into field arguments for limits in local currency)
401not_authorizedYour credentials are wrong
403forbiddenThe request you made is not allowed
404not_foundResource not found. Check the request URL

Example Error Responses

HTTP/1.1 412 Precondition Failed
Content-Type: application/json
{
  "status": 412,
  "type": "sender_unidentified",
  "description":"Sender not identified",
  "arguments": {}
}
codetypeDescription
412receiver_unidentifiedWe couldn't identify the customer's MSISDN. Make sure the MSISDN is correct. If problem persists, contact us
412receiver_net_not_memberThe customer is a subscriber of a network which is not available through Coowry. Field arguments contains the mccmnc of the network
412sender_not_enough_balanceYou don't have enough airtime in your Coowry account for the subscriber's network. Contact us for more information

Callbacks

Coowry will make callbacks to a URI of your choice to notify you of certain events (eg. payment confirmation, customer preapproval...).

All callbacks are made to a single URI that you can change at any time, and are signed so you can verify their authenticity.

Callbacks consist of POST requests with a pre-defined format to which your servers must reply with a HTTP status codes 200 OK or 204 No Content.

Setting your callback URI

You are responsible for setting your callback URI. This also means you can change it anytime.

Every time the callback URI is set, a new callback secret will be generated. You can always reset the callback if you feel the secret has been compromised.

Request

To set or change your callback URI, you must make a POST request to /agents/callbacks,

Example Request

HTTP/1.1 POST https://api.coowry.com/v2/agents/callbacks
Content-Type: application/json
{
  "callback_uri": "https://mycompany.com/callbacks"
}

Only one parameter must be encoded in the request body,

ParameterDescriptionNotes
callback_uriThe callback URIProtocol must be included, ie. https://mycompany.com/callbacks instead of mycompany.com/callbacks. Only https is available at the moment.

The body of the request must be encoded in application/json. The Content-Type header should be set accordingly.

Response

Example Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "callback_uri": "https://mycompany.com/callbacks",
  "callback_secret": "mwwzx6cuu5hjjpiv"
}

The Coowry API will return a JSON object with two fields:

ParameterDescription
callback_uriSame as provided in the request
callback_secretThe secret that will be used to calculate the signature for callbacks and verify that the request originated in the Coowry API

You can renew the secret at any time by repeating the previous request.

Callback request format

Callback example

You will receive the following request at your callback URI

HTTP/1.1 POST
Content-Type: application/json
{
  "event": "trade_status_changed",
  "signature": "9e4b6b9143076547f0b8331514a6260bc428f777",
  "payload": {
               "id": "tr-la2js1mlrkrk",
               "reference": "REF-123456789",
               "status": "authorized",
               "failure": null
             }
}

The body of this request is a JSON object with the following fields,

ParameterDescriptionNotes
eventThe event that triggered this callbackSee section Events for a list of existing events
payloadThe payload of the callbackA JSON object containing the information specific to the event
signatureSignature used to verify that the call originated from Coowry's serversSee section Calculating the signature for more info on how to calculate the signature

If the response is something else, Coowry will reattempt the callback three times. If still unsuccessful, we will notify you by another channel (eg. an email from the Coowry team).

Calculating the signature

Calculating the signature

APPEND THE FIELDS IN ALPHABETICAL ORDER (field=value)

  failure=null + id=tr-la2js1mlrkrk + reference=REF-123456789 + status=authorized

ADD SECRET AT THE END

  failure=nullid=tr-la2js1mlrkrkreference=REF-123456789status=authorized + av56cxsa1fyrbtc5

PERFORM SHA1 DIGEST

  sha1 ( failure=nullid=tr-la2js1mlrkrkreference=REF-123456789status=authorizedav56cxsa1fyrbtc5 ) = 9e4b6b9143076547f0b8331514a6260bc428f777

The signature is calculated by combining the callback secret and the fields of the payload. A new callback secret is generated every time you set a new callback URI.

To calculate the signature,

For example, the signature for the callback in the example was calculated by running a SHA1 digest over the following string:

failure=nullid=tr-la2js1mlrkrkreference=REF-123456789status=authorizedav56cxsa1fyrbtc5

where av56cxsa1fyrbtc5 is the callback secret.

Events

This section contains a detailed description of all the events that will trigger a callback notification, along with the format of the payload for each event.

Changes in customer's preapproval

Callback example

HTTP/1.1 POST
Content-Type: application/json
{
  "event": "preapproval_status_changed",
  "signature": "3766bb2df0850e459e16deb00171a82d69cfd022",
  "payload": {
               "id": "RdeIQOaQEPUf",
               "reference": "REF-12345678",
               "active": "false"
             }
}

Coowry will notify you every time a customer preapproves your payments or cancels his preapproval.

The field event will be preapproval_status_changed.

In this case, the field payload will be a JSON object with the following fields,

ParameterDescriptionNotes
idThe preapproval idSame as returned during the preapproval process
referenceProvided when creating the preapprovaleg. your internal customer id. null if not used
activeThe status of the preapproval. true if still active, false otherwiseIf false, attempting to execute a trusted payment with this customer will return an error

Transaction completion or failure

Callback example

HTTP/1.1 POST
Content-Type: application/json
{
  "event": "trade_status_changed",
  "signature": "9e4b6b9143076547f0b8331514a6260bc428f777",
  "payload": {
               "id": "tr-la2js1mlrkrk",
               "sort": "p2b",
               "reference": "REF-123456789",
               "status": "authorized",
               "failure": null
             }
}

Coowry will notify you when a payment or settlement you have requested is completed or it fails.

Even in cases where the outcome of the transaction is returned synchronously (eg. settlements, trusted payments...), a notification is still triggered to protect from a failure in the connection.

The field event will be trade_status_changed.

In this case, the payload field will be a JSON object with the following fields,

ParameterDescriptionNotes
idCoowry's transaction identification codeeg. tr-la2js1mlrkrk
sortThe transaction's sortp2b indicates a payment, b2p indicates a settlement
referenceMerchant transaction Id.This will be the same as the field reference you provided during the payment request
statusStatus of the transactionWill always be authorized or failed
failureFailure reason (if status=failed)If the transaction failed this field contains the reason for the failure, null otherwise

The field status represents the status of the transaction. It will always be authorized for settlements (sort=b2p).

If the transaction is a payment (sort=p2b) and status=failed and, the reason for failure can be one of the following,

FailureReason
sender_not_billedAn error ocurred when trying to charge the customer's phone. Try again and contact us problem persists
sender_not_enough_balanceThe user did not have enough balance in his prepaid account to complete the transaction
cancelledThe user cancelled the transaction
token_timeoutThe transaction expired