Articles on: Artificial Intelligence (AI)
This article is also available in:

Outgoing webhooks

Webhooks


Webhooks allow you to connect Fotostudio to external tools like Make, Zapier, n8n or your own backend. For each important event (new contact, paid invoice, signed contract...), Fotostudio automatically sends data to the URL of your choice.



Configure a webhook


Go to Modules → Outgoing webhooks and click New webhook.


Fill in the following fields:


Field

Description

Label

A name to help you identify it (e.g. "Make – invoices")

Destination URL

The HTTPS URL provided by your tool (Make, Zapier...)

Events

The events to listen for (you can check multiple)


A secret is automatically generated upon creation. Copy it immediately: it won't be displayed again. It's used to verify that calls actually come from Fotostudio.



Available events


Event

Triggered when...

contact.created

A new contact is created

contact.updated

A contact is modified (details, info...)

project.created

A new session is created

project.status_changed

The status of a session changes

project.confirmed

A session is confirmed

invoice.created

An invoice is created

invoice.paid

An invoice is marked as paid

payment.created

A payment is recorded

estimate.accepted

A quote is accepted by the client

estimate.refused

A quote is refused by the client

contract.signed

A contract is signed



Format of sent data


Each call is a POST in JSON with the following structure:


{
"event": "invoice.paid",
"timestamp": "2026-06-12T10:30:00Z",
"data": {
...
}
}


HTTP headers


Header

Value

Content-Type

application/json

X-FS-Event

Event name (e.g. invoice.paid)

X-FS-Signature

sha256=<hmac> (HMAC-SHA256 signature of the body)

X-FS-Delivery-Id

Unique delivery identifier


Verify the signature


The signature in X-FS-Signature is calculated as follows:


HMAC-SHA256(secret, body_json)


In Node.js for example:


const crypto = require('crypto')
const sig = 'sha256=' + crypto.createHmac('sha256', SECRET).update(rawBody).digest('hex')
if (sig !== req.headers['x-fs-signature']) throw new Error('Invalid signature')



Data details by event


contact.created / contact.updated


{
"id": 123,
"firstname": "Marie",
"lastname": "Dupont",
"email": "marie@example.com",
"phone": "+33 6 12 34 56 78",
"company": "Studio Photo",
"street": "12 rue de la Paix",
"zipcode": "75001",
"city": "Paris",
"country": "France",
"created_at": "2026-01-15T09:00:00Z",
"url": "https://www.fotostudio.io/app/contacts/123"
}


project.created / project.status_changed / project.confirmed


{
"id": 456,
"name": "Mariage Dupont",
"start_time": "2026-07-20T14:00:00Z",
"end_time": "2026-07-20T18:00:00Z",
"project_type": "Mariage",
"status": "Confirmé",
"validated": true,
"location": "Château de Versailles",
"contact_id": 123,
"created_at": "2026-01-15T09:00:00Z",
"url": "https://www.fotostudio.io/app/projects/456"
}


invoice.created / invoice.paid


{
"id": 789,
"numero": "F2026-042",
"title": "Mariage Dupont",
"invoice_date": "2026-06-01",
"total_price": 1500.00,
"amount_to_pay": 750.00,
"paid": false,
"draft": false,
"contact_id": 123,
"project_id": 456,
"created_at": "2026-06-01T10:00:00Z",
"url": "https://www.fotostudio.io/app/invoices/789"
}


amount_to_pay is the remaining balance to pay (total - payments already received).


payment.created


{
"id": 101,
"amount": 750.00,
"payment_date": "2026-06-10",
"payment_type": "Virement",
"invoice_id": 789,
"contact_id": 123,
"created_at": "2026-06-10T14:00:00Z"
}


estimate.accepted / estimate.refused


{
"id": 202,
"numero": "D2026-018",
"title": "Mariage Dupont",
"total_price": 1500.00,
"accepted": true,
"refused": false,
"accepted_at": "2026-06-05T16:00:00Z",
"contact_id": 123,
"project_id": 456,
"created_at": "2026-05-20T09:00:00Z",
"url": "https://www.fotostudio.io/app/estimates/202"
}


contract.signed


{
"id": 303,
"title": "Contrat Mariage Dupont",
"signed_at": "2026-06-08T11:30:00Z",
"project_id": 456,
"contact_id": 123,
"created_at": "2026-05-25T10:00:00Z",
"url": "https://www.fotostudio.io/app/contracts/303"
}



Delivery history


In each webhook's details page, the Logs tab displays the call history with:


  • date and time
  • triggered event
  • status (success / failure)
  • HTTP response code
  • error message in case of failure


In case of failure, Fotostudio automatically retries up to 3 times with exponential delay. You can also manually retry a call from the logs.



Using with Make


  1. In Make, create a new scenario and add a Webhooks → Custom webhook module
  2. Copy the URL generated by Make
  3. In Fotostudio, create a webhook with this URL and select the desired events
  4. Trigger a test event from Fotostudio (create a contact, for example)
  5. Make receives the data. You can then build your automation



Using with Zapier


  1. In Zapier, create a new Zap and choose Webhooks by Zapier → Catch Hook as the trigger
  2. Copy the URL provided by Zapier
  3. In Fotostudio, create a webhook with this URL
  4. Trigger a test event. Zapier automatically detects the data structure
  5. Configure your action (Google Sheets, Notion, Slack...)



FAQ


What happens if my server is unavailable?
Fotostudio retries 3 times with an increasing delay. After 3 attempts, the delivery is marked as failed but remains in the logs. You can relaunch it manually.


How quickly does my webhook need to respond?
Your endpoint must respond within 10 seconds. Beyond that, the request is considered failed.


Can I have multiple webhooks?
Yes, you can create as many webhooks as you want, each with its own events and URL.


How do I temporarily disable a webhook?
In the list, use the toggle button to enable or disable a webhook without deleting it.

Updated on: 26/06/2026

Was this article helpful?

Share your feedback

Cancel

Thank you!