Airtm Webhooks API

Webhooks are how services notify each other of events. At their core they are just a POST request to a pre-determined endpoint. The endpoint can be whatever you want, and you can just add them from the UI. You normally use one endpoint per service, and that endpoint listens to all of the event types. For example, if you receive webhooks from Airtm, you can structure your URL like: `https://www.example.com/webhooks/airtm`. The way to indicate that a webhook has been processed is by returning a 2xx (status code 200-299) response to the webhook message within a reasonable time-frame (15s). It's also important to disable CSRF protection for this endpoint if the framework you use enables them by default. Another important aspect of handling webhooks is to verify the signature and timestamp when processing them. You can learn more about it in the signature verification section. # Adding an Endpoint In order to start listening to messages, you will need to configure your endpoints. Adding an endpoint is as simple as providing a URL that you control and selecting the event types that you want to listen to. You can do this by navigating to the "Webhooks" section in the [enterprise dashboard](https://enterprise.airtm.com/settings/webhooks). If you don't specify any event types, by default, your endpoint will receive all events, regardless of type. This can be helpful for getting started and for testing, but we recommend changing this to a subset later on to avoid receiving extraneous messages. If your endpoint isn't quite ready to start receiving events, you can press the "with Svix Play" button to have a unique URL generated for you. You'll be able to view and inspect webhooks sent to your Svix Play URL, making it effortless to get started. # Testing Endpoints Once you've added an endpoint, you'll want to make sure its working. The "Testing" tab lets you send test events to your endpoint. After sending an example event, you can click into the message to view the message payload, all of the message attempts, and whether it succeeded or failed. # Verifying Signatures Webhook signatures let you verify that webhook messages are actually sent by us and not a malicious actor. For a more detailed explanation, check out this article on [why you should verify webhooks](https://docs.svix.com/receiving/verifying-payloads/why). Our webhook partner Svix offers a set of useful libraries that make verifying webhooks very simple. Here is a an example using Javascript: ```javascript import { Webhook } from 'svix'; const secret = 'whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw'; // These were all sent from the server const headers = { 'svix-id': 'msg_p5jXN8AQM9LWM0D4loKWxJek', 'svix-timestamp': '1614265330', 'svix-signature': 'v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=', }; const payload = '{"test": 2432232314}'; const wh = new Webhook(secret); // Throws on error, returns the verified content on success const payload = wh.verify(payload, headers); ``` For more instructions and examples of how to verify signatures, check out their [webhook verification documentation](https://docs.svix.com/receiving/verifying-payloads/how). # Retries We attempt to deliver each webhook message based on a retry schedule with exponential backoff. ## The schedule Each message is attempted based on the following schedule, where each period is started following the failure of the preceding attempt: - Immediately - 5 seconds - 5 minutes - 30 minutes - 2 hours - 5 hours - 10 hours - 10 hours (in addition to the previous) If an endpoint is removed or disabled delivery attempts to the endpoint will be disabled as well. For example, an attempt that fails three times before eventually succeeding will be delivered roughly 35 minutes and 5 seconds following the first attempt. ## Manual retries You can also use the application portal to manually retry each message at any time, or automatically retry ("Recover") all failed messages starting from a given date. # Troubleshooting Tips There are some common reasons why your webhook endpoint is failing: ## Not using the raw payload body This is the most common issue. When generating the signed content, we use the raw string body of the message payload. If you convert JSON payloads into strings using methods like stringify, different implementations may produce different string representations of the JSON object, which can lead to discrepancies when verifying the signature. It's crucial to verify the payload exactly as it was sent, byte-for-byte or string-for-string, to ensure accurate verification. ## Missing the secret key From time to time we see people simple using the wrong secret key. Remember that keys are unique to endpoints. ## Sending the wrong response codes When we receive a response with a 2xx status code, we interpret that as a successful delivery even if you indicate a failure in the response payload. Make sure to use the right response status codes so we know when message are supposed to succeed vs fail. ## Responses timing out We will consider any message that fails to send a response within 15 seconds a failed message. If your endpoint is also processing complicated workflows, it may timeout and result in failed messages. We suggest having your endpoint simply receive the message and add it to a queue to be processed asynchronously so you can respond promptly and avoiding getting timed out. # Failure Recovery ## Re-enable a disabled endpoint If all attempts to a specific endpoint fail for a period of 5 days, the endpoint will be disabled. To re-enable a disabled endpoint, go to the webhook dashboard, find the endpoint from the list and select "Enable Endpoint". ## Recovering/Resending failed messages If your service has downtime or if your endpoint was misconfigured, you probably want to recover any messages that failed during the downtime. If you want to replay a single event, you can find the message from the UI and click the options menu next to any of the attempts. From there, click "resend" to have the same message send to your endpoint again. If you need to recover from a service outage and want to replay all the events since a given time, you can do so from the Endpoint page. On an endpoint's details page, click "Options > Recover Failed Messages". From there, you can choose a time window to recover from. For a more granular recovery - for example, if you know the exact timestamp that you want to recover from - you can click the options menu on any message from the endpoint page. From there, you can click "Replay..." and choose to "Replay all failed messages since this time." # IP Addresses Webhooks are sent from the following IP addresses: - `44.228.126.217` - `50.112.21.217` - `52.24.126.164` - `54.148.139.208` - `2600:1f24:64:8000::/56`

Operations 1

GET /embedded/webhooks/portal-url Get portal URL #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/airtm-webhooks-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

airtm-webhooks-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Airtm Enterprise API V2 Webhooks API
  version: 1.155.0
  description: '# Introduction


    The Airtm Enterprise API enables organizations to send and receive payments globally through a simple REST API.'
  contact:
    name: Airtm Enterprise
    email: enterprise@airtm.com
    url: https://www.airtm.com
servers:
- url: https://api.enterprise.airtm.com/v2
- url: https://api.stg.enterprise.airtm.com/v2
tags:
- name: Webhooks
  description: Webhooks are how services notify each other of events.
paths:
  /embedded/webhooks/portal-url:
    get:
      operationId: GetPortalUrl
      responses:
        '200':
          description: Ok
          content:
            application/json:
              schema:
                properties:
                  url:
                    type: string
                required:
                - url
                type: object
        default:
          description: Error
          content:
            application/json:
              schema:
                properties:
                  code:
                    type: string
                    description: 'Machine-friendly error code


                      See the API error code catalog in the documentation for the endpoint surface you are using.'
                    example: '415096'
                  message:
                    type: string
                    description: Human-readable error message
                    example: Invalid email address
                  data:
                    $ref: '#/components/schemas/Record_string.unknown_'
                    description: Additional data related to the error
                    example:
                      email: invalid@address
                required:
                - code
                - message
                type: object
      description: Get a single-use URL for your account that you can open in your browser to configure your webhook endpoints.
      summary: Get portal URL
      tags:
      - Webhooks
      security:
      - embeddedAuth: []
      parameters: []
webhooks:
  payout.created:
    post:
      operationId: payout.created
      tags:
      - Webhooks
      summary: Payout Created
      description: 'Triggered when a payout has been created.

        Consider using this event to centralize payout tracking if you have multiple sources.'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - data
              - type
              additionalProperties: false
              properties:
                data:
                  $ref: '#/components/schemas/PayoutResponse'
                  description: Payout details
                type:
                  type: string
                  description: payout.created
                  example: payout.created
  payout.completed:
    post:
      operationId: payout.completed
      tags:
      - Webhooks
      summary: Payout completed
      description: A payout has completed
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - data
              - type
              additionalProperties: false
              properties:
                data:
                  $ref: '#/components/schemas/PayoutResponse'
                  description: Payout details
                type:
                  type: string
                  description: payout.completed
                  example: payout.completed
  payout.failed:
    post:
      operationId: payout.failed
      tags:
      - Webhooks
      summary: Payout failed
      description: A payout has failed
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - data
              - type
              additionalProperties: false
              properties:
                data:
                  $ref: '#/components/schemas/PayoutResponse'
                  description: Payout details
                type:
                  type: string
                  description: payout.failed
                  example: payout.failed
  payout.canceled:
    post:
      operationId: payout.canceled
      tags:
      - Webhooks
      summary: Payout canceled
      description: A payout has been canceled
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - data
              - type
              additionalProperties: false
              properties:
                data:
                  $ref: '#/components/schemas/PayoutResponse'
                  description: Payout details
                type:
                  type: string
                  description: payout.canceled
                  example: payout.canceled
  payin.created:
    post:
      operationId: payin.created
      tags:
      - Webhooks
      summary: Payin created
      description: 'Triggered when a payin has been created.

        Consider using this event to centralize payin tracking if you have multiple sources.'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - data
              - type
              additionalProperties: false
              properties:
                data:
                  $ref: '#/components/schemas/PayinResponse'
                  description: Payin details
                type:
                  type: string
                  description: payin.created
                  example: payin.created
  payin.confirmed:
    post:
      operationId: payin.confirmed
      tags:
      - Webhooks
      summary: Payin confirmed
      description: A payin has been confirmed
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - data
              - type
              additionalProperties: false
              properties:
                data:
                  $ref: '#/components/schemas/PayinResponse'
                  description: Payin details
                type:
                  type: string
                  description: payin.confirmed
                  example: payin.confirmed
  payin.failed:
    post:
      operationId: payin.failed
      tags:
      - Webhooks
      summary: Payin failed
      description: A payin has failed
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - data
              - type
              additionalProperties: false
              properties:
                data:
                  $ref: '#/components/schemas/PayinResponse'
                  description: Payin details
                type:
                  type: string
                  description: payin.failed
                  example: payin.failed
  payin.canceled:
    post:
      operationId: payin.canceled
      tags:
      - Webhooks
      summary: Payin canceled
      description: A payin has been canceled
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
              - data
              - type
              additionalProperties: false
              properties:
                data:
                  $ref: '#/components/schemas/PayinResponse'
                  description: Payin details
                type:
                  type: string
                  description: payin.canceled
                  example: payin.canceled
components:
  schemas:
    PayinResponse:
      description: 'A payin is a transaction that transfers funds from a user''s Airtm account to an enterprise''s account.

        Normally, the payin represents a purchase made by a user.'
      properties:
        id:
          $ref: '#/components/schemas/Uuid'
          description: The unique identifier for the payin.
        code:
          type: string
          description: 'An arbitrary string of the partner’s choosing. Used to identify and correlate Airtm purchases with partner records.


            > [!important]

            > Must be a unique.'
        hash:
          type: string
          description: Unique hash for the payin operation within the Airtm system.
        status:
          $ref: '#/components/schemas/PayinStatus'
        amount:
          type: number
          format: double
          description: Amount in USD that was transacted in the operation.
          example: 10
        netAmount:
          type: number
          format: double
          description: Amount in USD to be received by the enterprise
          example: 9.5
        airtmFee:
          type: number
          format: double
          description: Amount to be collected by Airtm as fee
          example: 0.5
        description:
          type: string
          description: 'A text string describing the purchase.


            > [!tip]

            > This text is displayed to the user when they are confirming the transaction.'
        items:
          items:
            $ref: '#/components/schemas/PayinItem'
          type: array
          description: An array of the items being purchased/bought.
        airtmUserId:
          $ref: '#/components/schemas/Uuid'
          description: The unique identifier for the AirTM user associated with this payin.
        airtmUserEmail:
          $ref: '#/components/schemas/Email'
          description: The email of the Airtm user associated with this payin.
        failureReason:
          type: string
          description: If the payin failed to complete, this field will describe why it failed.
        createdAt:
          type: string
          format: date-time
          description: Timestamp of when the payin was created.
        updatedAt:
          type: string
          format: date-time
          description: Timestamp of the last update made to the payin.
        confirmationUri:
          type: string
          description: A URL to redirect the user to when they confirm the transaction.
          format: url
        cancelUri:
          type: string
          description: A URL to redirect the user to when they cancel the transaction.
          format: url
      required:
      - id
      - code
      - status
      - amount
      - netAmount
      - airtmFee
      - description
      - items
      - createdAt
      - updatedAt
      - confirmationUri
      - cancelUri
      type: object
      additionalProperties: false
    PayoutStatus:
      description: "The current status of the payout.\n\n- `CREATED`: The payout instruction has been registered and is awaiting you to call the commit endpoint.\n- `COMMITTED`: The payout was committed and is in the process of being executed.\n- `PENDING`: Funds have been placed in escrow and waiting for the recipient to take the following action to complete the payout\n  1. If a new user, create an Airtm account.\n  2. If a user receiving an amount taking them over the $1,000 inflow threshold requiring KYC.\n  3. If a US user, complete KYC and configure payment method.\n- `COMPLETED`: The payout has been completed successfully, funds have been credited to the customer's account.\n- `CANCELED`: Payout has been canceled and funds have been returned to your account.\n- `FAILED`: The payout has failed and funds have been returned to your account.\n- `ERROR`: A temporary error state. Payouts in this state should be fixed and retried until they reach a final state (COMPLETED or CANCELED)."
      enum:
      - BRIDGE_COMPLETED
      - BRIDGE_CREATED
      - BRIDGE_FAILED
      - BRIDGE_MAX_RETRIES_REACHED
      - BRIDGE_USER_SIGNUP_PENDING
      - CANCELED
      - CANCEL_REQUESTED
      - COMMITTED
      - COMPLETED
      - COSMOEM_COMPLETED
      - CREATED
      - ERROR
      - FAILED
      - PENDING
      - PENDING_SIGNATURE
      - SIGNED
      - PENDING_USER_ACTION
      - PROCESSING
      type: string
      x-enum-varnames:
      - BRIDGE_COMPLETED
      - BRIDGE_CREATED
      - BRIDGE_FAILED
      - BRIDGE_MAX_RETRIES_REACHED
      - BRIDGE_USER_SIGNUP_PENDING
      - CANCELED
      - CANCEL_REQUESTED
      - COMMITTED
      - COMPLETED
      - COSMOEM_COMPLETED
      - CREATED
      - ERROR
      - FAILED
      - PENDING
      - PENDING_SIGNATURE
      - SIGNED
      - PENDING_USER_ACTION
      - PROCESSING
    PayinStatus:
      description: 'The current status of the payin


        - `CREATED`: The payin has been created but not yet confirmed.

        - `CONFIRMED`: The payin has been confirmed and is ready for processing.

        - `CANCELED`: The payin has been canceled by the user or system.

        - `PROCESSING`: The payin is currently being processed.

        - `FAILED`: The payin has failed due to an error.

        - `BRIDGE_FAILED`: The payin has failed due to an error in Bridge.

        - `BRIDGE_CANCELED`: The payin has been canceled due to an error in Bridge.'
      enum:
      - CREATED
      - CONFIRMED
      - CANCELED
      - PROCESSING
      - FAILED
      - BRIDGE_FAILED
      - BRIDGE_CANCELED
      type: string
      x-enum-varnames:
      - CREATED
      - CONFIRMED
      - CANCELED
      - PROCESSING
      - FAILED
      - BRIDGE_FAILED
      - BRIDGE_CANCELED
    Record_string.unknown_:
      properties: {}
      additionalProperties: {}
      type: object
      description: Construct a type with a set of properties K of type T
    KycInformation:
      description: 'Represents the user''s KYC information for a payout.


        > [!TIP]

        > Only available in `payout.completed` webhook and only if ID verification is enabled in your account.

        > If you want access to this information, please contact [enterprise@airtm.io](mailto:enterprise@airtm.io)

        Represents the user''s KYC information for a payout.


        > [!TIP]

        > Only available in `payout.completed` webhook and only if ID verification is enabled in your account.

        > If you want access to this information, please contact [enterprise@airtm.io](mailto:enterprise@airtm.io)'
      properties:
        fullName:
          type:
          - string
          - 'null'
        birthDate:
          type:
          - string
          - 'null'
        identificationNumber:
          type:
          - string
          - 'null'
        countryCode:
          type:
          - string
          - 'null'
        state:
          type:
          - string
          - 'null'
      required:
      - fullName
      - birthDate
      - identificationNumber
      - countryCode
      type: object
      additionalProperties: false
    PayinItem:
      description: An item within a payin transaction
      properties:
        description:
          type: string
          description: An arbitrary string describing the individual item.
        amount:
          type: number
          format: double
          description: The price in USD of the individual item.
          example: 10
          minimum: 0.01
        quantity:
          type: number
          format: double
          description: 'The number of items being purchased.

            This will be multiplied with the ''amount'' value to calculate the total.'
          example: 1
          minimum: 1
        id:
          type: string
          description: The unique identifier for the item
          format: uuid
        payinId:
          type: string
          description: The unique identifier for the payin.
          format: uuid
      required:
      - description
      - amount
      - quantity
      - id
      - payinId
      type: object
      additionalProperties: false
    PayoutResponse:
      description: Represents a Payout Object
      properties:
        id:
          $ref: '#/components/schemas/Uuid'
          description: This is the unique identifier for the payout.
        bulkPayoutId:
          $ref: '#/components/schemas/Uuid'
          description: The identifier of the bulk payout that created this payout.
        hash:
          type: string
          description: Unique hash for the payout operation within the Airtm system.
        code:
          type: string
          description: A unique code used to identify the payout.
        airtmUserId:
          $ref: '#/components/schemas/Uuid'
          description: This is the unique identifier for the AirTM user associated with this payout.
        airtmUserEmail:
          $ref: '#/components/schemas/Email'
          description: This is the email of the Airtm user associated with this payout.
        requireIdVerified:
          type: boolean
          description: Whether the recipient must be ID-verified to receive the funds
          default: false
        notes:
          type: string
          description: An arbitrary string describing the payment. This information is displayed to the recipient.
        internalNote:
          type: string
          description: The description of the payout; visible to internal users
        status:
          $ref: '#/components/schemas/PayoutStatus'
        grossAmount:
          type: number
          format: double
          description: amount originally intended for the payout
          example: 10
        amount:
          type: number
          format: double
          description: amount to be deducted from the enterprise account (grossAmount - enterpriseFee)
          example: 9.5
        netAmount:
          type: number
          format: double
          description: amount received by the user (grossAmount - enterpriseFee - airtmFee)
          example: 9
        airtmFee:
          type: number
          format: double
          description: The airtm fee applied to the payout
          example: 0.5
        enterpriseFee:
          type: number
          format: double
          description: The enterprise fee applied to the payout
          example: 0.5
        reasonCode:
          type: string
          description: Machine-friendly code relating to the reason why the payout has the current status
          example: 522443
        reasonDescription:
          type: string
          description: Human-readable message describing the reason why the payout has the current status
        kycInformation:
          $ref: '#/components/schemas/KycInformation'
        createdAt:
          type: string
          format: date-time
          description: Timestamp of when the payout was created.
        updatedAt:
          type: string
          format: date-time
          description: Timestamp of the last update made to the payout.
      required:
      - id
      - airtmUserId
      - airtmUserEmail
      - status
      - grossAmount
      - amount
      - netAmount
      - createdAt
      - updatedAt
      type: object
      additionalProperties: false
    Email:
      type: string
      pattern: ^(.+)@(.+)$
    Uuid:
      type: string
      format: uuid
      pattern: ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
x-tagGroups:
- name: Payout Operations
  tags:
  - Payouts
  - Bulk Payouts
  - Users
- name: Payin Operations
  tags:
  - Payins
- name: Account
  tags:
  - Me
  - Deposits
  - Reports
- name: Direct Withdrawal
  tags:
  - External Bank Account
  - External Crypto Account
  - Withdrawals
- name: Webhooks
  tags:
  - Webhooks