Payments

At the heart of Paidy is a payments flow that enables you to easily and securely handle payments at your webstore.


  How do payments work at Paidy

Standard payments

A standard payment is a one-time purchase. Standard payments are usually created by the consumer via Paidy Checkout and managed by the merchant via the Paidy API.

[payments overview diagram]

Flow of a typical standard payment:

  • With just a few clicks, a consumer quickly and easily checks out using Paidy Checkout.
  • Paidy authenticates the consumer via SMS and then authorizes the payment.
  • You process and ship the order using your existing order management system and when you are ready to charge the consumer, you capture the payment via the API.

Payments can also be cancelled and refunded using the Paidy API.

Token payments

Token payments are a way of handling recurring payments at your website. Tokens are created during the checkout process. Once the token has been successfully created, you can use the Paidy API to create new payments using that token. The token is a link to the consumer’s Paidy account.

[payments overview diagram]

Flow of a typical token payment (including token creation):

  • A consumer checks out using Paidy Checkout.
  • Paidy authenticates the consumer and creates the token.
  • You create a payment using this token via the API. Paidy authorizes and creates the payment.
  • When you are ready to charge the consumer, you capture the payment via the API.
  • In the future, when you want to create new payments using this token, you simply send create and capture requests via the API.

Once a payment is created, it is managed in the same way as a standard payment via the Paidy API.

Lifecycle of a payment

[payment lifecycle diagram]

 

  • STATE

    DESCRIPTION

  • AUTHORIZED

    When a new payment is successfully created, it is in the AUTHORIZED state.
    Valid API requests for a payment in the AUTHORIZED state: capture, close, retrieve, update

  • REJECTED

    A payment is in this state if it fails the authorization process.
    When a payment is in the REJECTED state, the only valid API request is: retrieve

  • CLOSED

    A payment that has been captured or closed is in this state.
    Valid API requests for a payment in the CLOSED state: refund, retrieve, update


  Payments API overview

The Paidy API provides an easy and secure way to manage payment requests. It is a REST API, with request and response data formatted as JSON. Using the API, you can:

Secure communication

TLS is an industry standard protocol for encrypting network communications and providing end-to-end security over the Internet. The Paidy API supports TLS version 1.1 and higher. Additionally, we rely on HTTPS to ensure all data is transmitted securely.

API version

The current version of the API is 2018-04-10. You can set the version number in the header of each request that is made to the API. If the API version is not set in the header, the system will use the API version set in the Merchant Dashboard. If nothing is set in the Merchant Dashboard, the system will default to the current version of the API.

Metadata field

The token, payment, captures, and refunds objects all contain a metadata field. You can use this field to store additional information about an object. If, for example, the Paidy API does not have a field to which you can map data you need to store, you can use this field to hold a set of key-value pairs. Each metadata field is limited to 20 key-value pairs.

Example:


"metadata": {
  "key1": "value1",
  "key2": "value2"
}

  • Metadata for the token object is set via Paidy Checkout.
  • Metadata for the payment object is set via Paidy Checkout and can be updated via update request. You can update the metadata for the payment as many times as you like, however take care because each time, the existing metadata will be completely overwritten.
  • Metadata for the captures object is set via the capture request. Once the data is set, it cannot be updated.
  • Metadata for the refunds object is set via the refund request. You can update the metadata for the refund as many times as you like, however take care because each time, the existing metadata will be completely overwritten. (Also, be careful when submitting a refund request, if you do not specify an amount, the system will assume the total payment amount is to be refunded.)

UTF-8 encoding

Sometimes Japanese characters sent in the JSON can be garbled and replaced with with random characters (such as a question mark or a box). To ensure that the text is transmitted correctly and displayed correctly at Paidy’s user interfaces, make sure it is UTF-8 encoded.


  Creating a standard payment

Standard payments are created by the consumer via Paidy Checkout. If successful, the payment has a status of AUTHORIZED. When you are ready to charge a consumer, use the Paidy API to capture the payment.

Remember authorized payments expire and you cannot capture the payment after the expiration date. To determine when a payment expires, send a GET request from your backend system to the /payments/{id} endpoint, where {id} is the payment ID. If the request is successful, it returns the full payment object. The expires_at field indicates when the payment will expire.


  Creating a token payment

Token payments are created via the API using a token. Both the token and the consumer who owns the token must be active. To create the payment, send a POST request to the /payments endpoint. The body of the request must contain the following fields.

  • PARAMETER

    DESCRIPTION

  • token_id

    string

    REQUIRED

    Paidy-generated token ID, beginning with tok_.

  • amount

    double

    REQUIRED

    Total payment amount, including tax, shipping, and excluding any discounts.

  • currency

    string

    REQUIRED

    ISO 4217 currency code for this order; set to JPY.

  • description

    string

    optional

    Description for the payment.

  • store_name

    string

    optional

    Name of the store. This is displayed in the Checkout app header, at MyPaidy, and the Merchant Dashboard.

  • buyer_data

    object

    REQUIRED

    Buyer_data object containing information about the consumer's purchasing history.

  • order

    object

    REQUIRED

    Order data.

  • shipping_address

    object

    REQUIRED

    Consumer's shipping address.

  • metadata

    object

    optional

    Merchant-defined data about the object. This field is a key-value map, limited to 20 keys.

Example:


curl -X "POST" "https://api.paidy.com/payments" \
  -H "Content-Type: application/json" \
  -H "Paidy-Version: 2018-04-10" \
  -H "Authorization: Bearer $secret_key" \
  -d $'{
         "token_id": "tok_WL0GoQwAAAoA1beX",
         "amount": 12800,
         "currency": "JPY",
         "description": "Description",
         "store_name": "Paidy sample store",
         "buyer_data": {
            "user_id": "yamada_taro",
            "age": 29,
            "age_platform": 50,
            "days_since_first_transaction": 29,
            "ltv": 250000,
            "order_count": 1000,
            "last_order_amount": 20000,
            "last_order_at": 20,
            "order_amount_last3months": 15000,
            "order_count__last3months": 5,
            "additional_shipping_addresses": [{
                "line1": "AZABUビル 2F",
                "line2": "東麻布2-10-1",
                "city": "港区",
		        "state": "東京都",
		        "zip": "106-0023"
            }],
            "billing_address": {
                "line1": "AXISビル 10F",
                "line2": "六本木4-22-1",
                "city": "港区",
                "state": "東京都",
                "zip": "106-2004"
            },
            "delivery_locn_type": "office",
            "gender": "Male",
            "subscription_counter": 2,
            "previous_payment_methods": {
                "credit_card_used": false,
                "cash_on_delivery_used": true,
                "convenience_store_prepayment_used": true,
                "carrier_payment_used": false,
	            "bank_transfer_used": false,
	            "rakuten_pay_used": true,
	            "line_pay_used": false,
	            "amazon_pay_used": false,
	            "np_postpay_used": false,
	            "other_postpay_used": false
            },
            "number_of_points": 8023,
            "order_item_categories": ["sunglasses", "contact lenses"]
         },
         "order": {
             "items": [ {
                "id": "PDI001",
                "quantity": 1,
                "title": "Paidyスニーカー",
                "unit_price": 12000,
                "description": "Paidyスニーカー"
             } ],
             "order_ref": "88e021674",
             "shipping": 500,
             "tax": 300
         },
         "shipping_address": {
             "line1": "AXISビル 10F",
             "line2": "六本木4-22-1",
             "city": "港区",
             "state": "東京都",
             "zip": "106-2004"
         },
         "metadata": {}
      }'

Paidy does a series of checks including verifying that both the token and consumer accounts are active. If all the checks pass, the payment is created and has a status of AUTHORIZED. When you are ready to charge a consumer, use the Paidy API to capture the payment.

Remember authorized payments expire and you cannot capture the payment after the expiration date. To determine when a payment expires, send a GET request from your backend system to the /payments/{id} endpoint, where {id} is the payment ID. If the request is successful, it returns the full payment object. The expires_at field indicates when the payment will expire.


  Capturing a payment

When you are ready to charge the consumer, you perform a capture request.

A consumer is not charged anything until a payment is captured. This provides you with the flexibility to charge consumer according to your order processing workflow, e.g., you can choose to charge a consumer as soon as a payment is authorized or you can wait until after an order has shipped.

If the capture request is successful, only the amount of money captured will be confirmed as payment to the merchant and charged to the consumer.

Any payment that is open can be captured, i.e., a payment that was authorized and has not expired. (By default, all authorized requests automatically expire. The expiration period is specified in your contract and after this period, you can no longer capture the order.)

payment capture

To capture a payment, send a POST request to the /payments/{id}/captures endpoint, where {id} is the Paidy payment ID. The body of the request can be empty or contain the metadata field. This field is a key-value map, limited to 20 keys, that contains additional data about the capture object. For example:


  curl -X "POST" "https://api.paidy.com/payments/pay_WD1KIj4AALQAIMtZ/captures" \
    -H "Content-Type: application/json" \
    -H "Paidy-Version: 2018-04-10" \
    -H "Authorization: Bearer $secret_key" \
    -d $'{"metadata": {"key1": "value1","key2": "value2"}}'

Paidy verifies the payment is authorized and creates the capture. You will immediately receive the result of the request - either a payment object upon success or an error object upon failure. If successful, the payment object contains the capture data, including a unique capture ID beginning with cap_. Be sure to save the capture ID somewhere in your system; it is required if you need to make a refund request against this payment.

When a payment is fully captured, the payment status is automatically updated to CLOSED.


  {
    "id":"pay_WFDYLhEAAEQA42Dw",
    "created_at":"2018-06-14T05:27:10.063Z",
    "expires_at":"2018-07-13T05:28:32.143Z",
    "amount":39800,
    "currency":"JPY",
   "description":" ",
    "store_name":"Paidy sample store",
    "test":true,
    "status":"closed",
    ...,
    "captures":[
      {
        "id":"cap_WFIk5yIAACIAC6n3",
       "created_at":"2018-06-15T05:06:47.189Z",
       "amount":39800,
       "tax":300,
       "shipping":500,
       "items":[
         {
           "id":"PDI001",
           "title":"スニーカー",
           "description":" ",            
            "unit_price":10000,
           "quantity":1
         },{
           "id":"EXC002",
           "title":"エクスコスニーカー",
           "description":" ",
           "unit_price":15000,
           "quantity":2
         },{
           "id":"CPN001",
           "title":"Discount",
           "description":" ",
           "unit_price":-1000,
           "quantity":1
         }
       ],
       "metadata":{"key1":"value1","key2":"value2"}
     }
   ], 
   ...
 }


  Refunding a payment

You can use the API to make full or partial refund. You can only refund a payment that has already been captured, and you need both the capture ID and the payment ID for the request. The refund is executed against the specified capture.

payment refund

To refund a payment, send a POST request to the /payments/{id}/refunds endpoint, where {id} is the Paidy payment ID. The body of the request must contain the capture ID. This is the only required field, but you can also (optionally) send:

  • The amount field. Paidy uses this field to determine whether the request is for a partial refund or full refund. If no amount is specified, Paidy refunds the full payment amount for that capture.
  • The reason field containing the reason for the refund.
  • The metadata field containing additional merchant-defined data about the refund. The field is a key-value map, limited to 20 keys.

For example:


  curl -X "POST" "https://api.paidy.com/payments/pay_WD1KIj4AALQAIMtZ/refunds" \
    -H "Content-Type: application/json" \
    -H "Paidy-Version: 2018-04-10" \
    -H "Authorization: Bearer $secret_key" \
    -d "{\"capture_id\":\"cap_WFIk5yIAACIAC6n3\",\"amount\":10000}"

It is possible to execute both a partial refund and a full refund against the same Paidy payment. For example, if the total payment amount is 10,000 yen, you can execute a partial refund for 3,000 yen by sending a refund request with amount set to 3000. Later you can send a full refund request (with no amount specified) and the remaining 7,000 yen will be refunded. It is not possible to execute a partial refund request after a full refund request.

If a refund request is successful, Paidy returns the updated payment object including the refund data. Each refund is assigned a unique refund ID, beginning with ref_.


  {
    "id":"pay_WFDYLhEAAEQA42Dw",
    ...
    "refunds":[
      {
        "id":"ref_WFImZyIAAD8AC6pC",
        "created_at":"2018-06-15T05:13:11.800Z",
        "capture_id":"cap_WFIk5yIAACIAC6n3",
         "amount":10000,
        "reason":"unknown",
        "metadata":{}
       }
    ],
    ...
  }

Since a refund request is an action against a specific capture, the payment status is not affected by a refund request.


  Retrieving a payment

To view the details for a payment, retrieve the payment by sending a GET request to the Payments endpoint. You can retrieve any payment that has a valid payment ID. Paidy returns the full payment object.

To determine the status of a payment, look at the full payment object. For example:

  • A payment with a status of AUTHORIZED was authorized by Paidy, but has not yet been captured.
  • A payment with a status of CLOSED that does not contain a captures object was canceled.
  • A payment with a status of CLOSED that also contains a captures object was captured. The payment may or may not have a partial or full refund depending on whether the payment also contains a refunds object.

retrieve payment

To retrieve a payment, send a GET request to the /payments/{id} endpoint, where {id} is the Paidy payment ID and the body of the request is empty. For example:


  curl -X "GET" "https://api.paidy.com/payments/pay_WD1KIj4AALQAIMtZ" \
    -H "Content-Type: application/json" \
    -H "Paidy-Version: 2018-04-10" \
    -H "Authorization: Bearer $secret_key" \
    -d "{}"

If successful, Paidy returns the full payment object. For example:


  {
    "id":"pay_WFDYLhEAAEQA42Dw",
    "created_at":"2018-06-14T05:27:10.063Z",
     "expires_at":"2018-07-13T05:28:32.143Z",
    "amount":39800,
    "currency":"JPY",
    "description":" ",
    "store_name":"Paidy sample store",
    "test":true,
    "status":"closed",
    "tier":"classic",
    "buyer":{
      "name1":"山田 太郎",
      "name2":"ヤマダ タロウ",
      "email":"yamada@paidy.com",
      "phone":"818000000001"
    },
    "order":{
      "tax":300,
      "shipping":500,
      "order_ref":"88e021674",
      "items":[
        {
          "id":"PDI001",
          "title":"スニーカー",
          "description":" ",
          "unit_price":10000,
          "quantity":1
        },{
          "id":"EXC002",
          "title":"エクスコスニーカー",
          "description":" ",
          "unit_price":15000,
          "quantity":2
        },{
          "id":"CPN001",
          "title":"Discount",
          "description":" ",
          "unit_price":-1000,
          "quantity":1
        }
      ],
      "updated_at":" "
    },
    "shipping_address":{
      "line1":"AXISビル 10F",
      "line2":"六本木4-22-1",
      "city":"港区",
      "state":"東京都",
      "zip":"106-2004"
    },
    "captures":[
      {
        "id":"cap_WFIk5yIAACIAC6n3",
        "created_at":"2018-06-15T05:06:47.189Z",
        "amount":39800,
        "tax":300,
        "shipping":500,
        "items":[
          {
            "id":"PDI001",
            "title":"Paidyスニーカー",
            "description":" ",
            "unit_price":10000,
            "quantity":1
          },{
            "id":"EXC002",
            "title":"エクスコスニーカー",
            "description":" ",
            "unit_price":15000,
            "quantity":2
          }{
           "id":"CPN001",
           "title":"Discount",
           "description":" ",
           "unit_price":-1000,
           "quantity":1
         }
        ],
        "metadata":{}
      }
    ], 
    "refunds":[
      {
        "id":"ref_WFImZyIAAD8AC6pC",
        "created_at":"2018-06-15T05:13:11.800Z",
        "capture_id":"cap_WFIk5yIAACIAC6n3",
        "amount":10000,
        "reason":"unknown",
        "metadata":{}
      }
    ],
    "metadata":{}
  }


  Updating a payment

To update the order_ref, description, and/or metadata fields for a payment, you can use the /payments/{id} endpoint. These fields are initially set when creating the payment:

  • The order_ref field is an optional field that contains a merchant-defined order ID or reference. Some merchants use this field to store a unique identifier that maps the Paidy payment to an order in their system. At the time the order is placed, the merchant may not know the order reference and this endpoint allows them to update it after the payment has been authorized.
  • The description field is an optional field that contains a merchant-defined description for the payment. (Note this description is not visible at MyPaidy or the Merchant Dashboard.)
  • The metadata field is an optional field in the payment object that can be used to store additional merchant-defined data about a payment. The field is a key-value map, limited to 20 keys.

You can only use this endpoint to update these 3 fields. If you send other fields in the request, they will simply be ignored by Paidy.

The payment you want to update can have a status of AUTHORIZED or CLOSED.

update payment

Send a PUT request to the /payments/{id} endpoint, where {id} is the Paidy payment ID. The body of the the request must contain the fields to be updated order_ref, description, and/or metadata fields.
When you update a field, the existing values will be overwritten. So, if you are adding key-value pairs to an existing list in the metadata field, remember to include the existing key-value pairs in the update request.

You can update one or more of these fields in one PUT request. For example:


curl -X "PUT" "https://api.paidy.com/payments/pay_WD1KIj4AALQAIMtZ" \
  -H "Content-Type: application/json" \
  -H "Paidy-Version: 2018-04-10" \
  -H "Authorization: Bearer $secret_key" \
  -d "{\"order_ref":"88e021674",\"description":"スニーカーストア"\}"

If the update request is successful, Paidy returns the updated payment object.


  {
    "id":"pay_WFDYLhEAAEQA42Dw",
    "created_at":"2018-06-14T05:27:10.063Z",
     "expires_at":"2018-07-13T05:28:32.143Z",
    "amount":39800,
    "currency":"JPY",
    "description":"スニーカーストア",
    "store_name":"Paidy sample store",
    "test":true,
    "status":"closed",
    ...,
    "order":{
      "tax":300,
      "shipping":500,
      "order_ref":"88e021674",
      "items":[
        {
          "id":"PDI001",
          "title":"スニーカー",
          "description":" ",
          "unit_price":10000,
          "quantity":1
        },{
          "id":"EXC002",
          "title":"エクスコスニーカー",
          "description":" ",
          "unit_price":15000,
          "quantity":2
       }{
          "id":"CPN001",
          "title":"Discount",
          "description":" ",
          "unit_price":-1000,
          "quantity":1
         }
      ],
      "updated_at":" "
    },
    ...
  }


  Closing a payment

When a payment is fully-captured, it is automatically closed by Paidy. However, you can also send a request to the Close endpoint to manually close a payment that has been authorized, but not captured.

We highly recommend that when you receive an order cancellation from a consumer, you use this endpoint to close the order. Uncaptured payments are factored into the assessment Paidy performs for future payment authorizations, so to ensure that your consumers do not get rejected on a future order, you should close the payment.

If you want to cancel a payment that is already captured (i.e., has a status of CLOSED), do not use the Close endpoint. Instead use the Refunds endpoint.

payment closure

Send a POST request to the /payments/{id}/close endpoint, where {id} is the Paidy payment ID and the body of the request is empty. For example:


  curl -X "POST" "https://api.paidy.com/payments/pay_542e6dc6008a077a4de3/close" \
    -H "Content-Type: application/json" \
    -H "Paidy-Version: 2018-04-10"
    -H "Authorization: Bearer $secret_key" \
    -d "{}"

Paidy retrieves the payment and verifies that it is open. If the payment is closed, Paidy returns an error. Otherwise, Paidy closes the payment and returns the updated payment object.


  {
    "id":"pay_WFDYLhEAAEQA42Dw",
    "created_at":"2018-06-14T05:27:10.063Z",
    "expires_at":"2018-07-13T05:28:32.143Z",
    "amount":40800,
    "currency":"JPY",
    "description":"スニーカーストア",
    "store_name":"Paidy sample store",
    "test":true,
    "status":"closed",
    ...
  }