Skip to main content

Webhooks & Sales Notifications

Webhooks:

Use the webhooks to receive notification on events occurring in the Virtual Library.

As of now the supported events are the following:

  • A sale of a single publication.
  • A sale of a prepaid plan.
  • Monthly payment of a recurring plan.

A webhook is a POST request, whose body contains a parameter called “token”. This token is a JWT (JSON Web Token) that contains all the event information. The JWT are signed using the standard, with the algorithm HS256, and allow who uses to be certain that the webhook is coming from publica.la.

To use the webhooks system you need to provide an URL and create a key. The URL is the endpoint to whick we will send the webhook and the key will be used to sign the webhooks. Both the URL and the key can be managed on the /dashboard/settings#integrations inside your virtual library.

The only requirement is to receive a 2xx (200, 201, etc) notification after the webhook is sent. This way our system can understand the notification was received successfully. In case the response code is other the system will take the notification has failed and will make 2 new attempts with a 3 hours delay each.

Details of the implementation:

The body request of a webhook is a JSON with the following format:

{
"json": {
"token_type": "jwt",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}
}

The JWT on every webhook share some characteristics:

  • A value with the property “iss” to the string “farfalla”
  • Are valid for 5 minutes once created.
  • They have as value of the property "sub" the type of event, for example "sale".
  • They have as value of the property "aud" the slug of the library, for example "naciondigital".

Useful links:

Sales Notifications:

Sales Notifications can be transmitted through the Webhook system or by email.

As of now the supported events are the following:

  • A sale of a single publication.
  • A sale of a prepaid plan.
  • Monthly payment of a recurring subscription.

The system notifies each sale 20 minutes after these are confirmed. Offline payments (Rapipago, Easy Payment, etc.) can take up to 72 hours to be reported as "confirmed" by the provider. For recurring subscriptions, system will send notification each month when invoice paid successfully The payload of a Sale Notification is the same for both email and JWT mediums, it has the following format:

{
"event_type": "sale",
"event_subtype": "single",
"uuid": "0d2d4b9a-1660-4418-8f51-96840b780190",
"job_id": "1231412",
"queued_at": 1554388826,
"environment": "live",
"payload": {
"user": {
"external_id": null,
"uuid": "3909be20-ff61-4e14-8c8b-9fd334a9ecf6",
"email": "[email protected]",
"name": "Charles N Salinas",
"national_id": "123456",
"billing_information": {
"address_line_1": "Stoney Lane",
"address_line_2": "Farmers Branch",
"city": "Texas",
"state": "Texas",
"country": "EEUU",
"postal_code": "2285",
"other_information": null
}
},
"payment_details": {
"gateway": "stripe",
"method": "card"
"recurring_cycle": null,
"store": "Some store",
"content_owner": "Some store",
"status": "approved",
"sale_type": "retail",
"publicala_percentage": 10,
"exchange_rate": 1,
"payout_currency_id": "USD",
"payout_amount_in_cents": 1800
},
"user_plan": {
"uuid": "699ed863-0445-4570-9f6b-4fa0fd350052",
"plan_type": "single",
"currency_id": "USD",
"amount": 2000,
"gateway": "stripe",
"own_gateway" : 0
},
"issue": {
"external_id": "11241353",
"name": "EjemploPublicala",
"description": "",
"publication_date": "2018-07-16",
"prices": [
{
"currency_id": "ARS",
"amount": 20000
},
{
"currency_id": "USD",
"amount": 2000
}
],
"file_type": "pdf",
"reader_url": "https:\/\/farfalla.test\/reader\/ejemplopublicala",
"is_free_until": "2019-03-29",
"require_login_when_free": 0,
"is_free": 0.
"publishers": ["publisher 1", "publisher 2"],
"publishing_group": null
},
"plan": {
"type": "recurring",
"name": "Biblioteca Derecho Civil",
"detail": null,
"id": 432,
"external_id": 4412
},
"coupon": {
"code": "TESTCOUPONCOD111",
"amount": 50,
"uses": 2,
"use_limit": 10,
"valid_to": "2019-05-01"
}
}
}

Fields details:

  • type: string, this data is mandatory and will always be present.
  • subtype: string, this data is mandatory and will always be present.
  • uuid: string, the unique identifier of the notification.
  • job_id: job identifier,
  • queued_at: job execution timestamp,
  • payload: It is an object that contains
    • user: It is an object that contains
      • uuid: string, unique identifier unrepeatable.
      • email: string or null
      • external_id: string or null, will be present in the event that the user comes from some integration.
      • name: string or null, will be present in the event that the user completes his name in the billing information of his profile.
      • national_id: integer, the name of the user.
      • address_line_1: string or null, the address of the user.
      • address_line_2: string or null, the address complementary of the user.
      • city: string or null, the city of the user.
      • state: string or null, the state of the user.
      • country: string or null, the country of the user.
      • postal_code: string or null, the postal code of the user.
      • other_information: string or null, another billing information of the user.
    • payment_details: It is an object that contains
      • gateway: string
      • method: string
      • recurring_cycle: integer or null. Only for recurring subscriptions, it indicates the number of payments charged to that subscription.
      • store: string. Store name.
      • status: string
      • sale_type: string
      • publicala_percentage: integer. The % of the sale that correspond to publica.la
      • exchange_rate: float. Exchange rate of the sale currency/USD
      • payout_currency_id: string. The currency on which publica.la will pay the store
      • payout_amount_in_cents: integer. The amount that will be paid to the store, in cents
    • user_plan: It is an object that contains
      • uuid: string, unique identifier unrepeatable.
      • plan_type: string, always present.
      • currency_id: string, always present (ARS, USD, COP, PEN, MXN, EUR).
      • amount: integer in cents (500, would be 5 Argentine pesos).
      • gateway: string, means of payment used for sale (Mercadopago, Paypal, Payu or Stripe).
      • own_gateway: boolean, Indicate payment occur via tenant owned gateway or not.
    • issue: It is an object that contains: (Only for Single Product Notifications)
      • external_id: string or null, usually the ISBN of the publication.
      • name: string
      • description: string or null
      • publication_date: string, in "2013-09-13" format.
      • prices: array of objects that contain currency type and amount in cents
        • currency_id: string, always present (ARS, USD, COP, PEN, MXN, EUR).
        • amount: integer in cents (500, would be 5 Argentine pesos).
      • file_type: string, is always present (pdf or epub).
      • reader_url: string, URL to the publication in the reader.
      • is_free_until: string or null, in "2013-09-13" format. This data is used to indicate to what date a publication is free.
      • require_login_when_free: true or false, indicates if it is necessary to log in to the system to be able to read the free publication.
      • is_free: true or false, indicates if the publication is free and freely accessible.
      • publishers: array of strings. List of issues publishers
      • publishing_group: string. Issue's publishing group taxonomy
    • plan: It is an object that contains: (Only for Subscriptions Notifications)
      • type: Type of the plan, Recurring, Prepaid or External
      • name: Name of the plan as displayed in the dashboard
      • detail: Detailed description of the plan
      • id: Unique identifier of the plan
      • external_id: Unique identifier of the plan set by administrator
    • coupon: it is an optional object that contains
      • code: string, code generated for the coupon always present,
      • amount: integer, percentage of discount applied, always present,
      • uses: integer, number of times the coupon has been used, always present,
      • use_limit: integer, maximum number of times that the coupon can be used, optional,
      • valid_to: string, maximum coupon use date, optional