# Geri çağırmayı alın ve doğrulayın

Node veya Python'da küçük bir alıcı çalıştırın, her geri çağırmanın imzasını çalışma alanınızın imzalama anahtarıyla kontrol edin ve bir istek bittiğinde formbase'in gönderdiği yanıtları okuyun.

## Geri çağırmayı alın ve doğrulayın

callbackUrl'li bir istek, o URL'ye imzalı bir POST ile sona erer: alıcı gönderdiğinde yanıtlarla, ya da süresinin dolduğu veya iptal edildiği haberiyle. Bu kılavuz makinenizde bir alıcı çalıştırır, imzayı kontrol eder ve yanıtları yazdırır.

<p>
  <a href="/tr/guides/rest-api/send-a-request">REST API ile istek gönderin</a>'deki gibi bir API token'ına ve yayınlanmış bir forma, ayrıca
  makinenizde Node veya Python'a ihtiyacınız var. Bir geri çağırmanın ne taşıdığı ve yeniden denemelerin nasıl çalıştığı{' '}
  <a href="/tr/requests/callbacks">Geri çağırmalar ve imzalama</a>'dadır.
</p>

<h2 id="secret">1. İmzalama anahtarını kopyalayın</h2>

<p>
  formbase her geri çağırmayı çalışma alanınızın istek imzalama anahtarıyla imzalar. Çalışma alanı kenar çubuğunda{' '}
  <strong>OAuth ve API Anahtarları</strong>'nı açın ve <strong>İstek imzalama anahtarı</strong> kartını bulun:
</p>

<p>Kopyalama düğmesine tıklayın ve anahtarı alıcınızın çalışacağı terminaldeki bir ortam değişkeninde saklayın:</p>

```
export FORMBASE_SIGNING_SECRET='rqs_...'
```

> ⚠️ **Onu yeniden oluşturmayın**
> <p>
>     Üçüncü düğme yeni bir anahtar oluşturur ve eskisi, zaten yolda olan geri çağırmalar için bile anında çalışmayı durdurur. Bu kılavuzu
>     izlemek için buna ihtiyacınız yok.
>   </p>

<h2 id="receiver">2. Alıcıyı yazın</h2>

<p>
  <code>verify</code> fonksiyonunu <a href="/tr/requests/callbacks#verify">Geri çağırmalar ve imzalama</a>'dan alıcınızın yanına kaydedin:{' '}
  <code>import</code> kullandığından Node için <code>verify.mjs</code> olarak, ya da Python için <code>verify.py</code> olarak. Alıcı ham
  gövdeyi okur, imzayı kontrol eder ve ancak o zaman JSON'u ayrıştırır:
</p>

  
    
```
import http from 'node:http'
const secret = process.env.FORMBASE_SIGNING_SECRET
http
  .createServer((req, res) => {
    const chunks = []
    req.on('data', (chunk) => chunks.push(chunk))
    req.on('end', () => {
      const rawBody = Buffer.concat(chunks).toString('utf8')
      const signature = req.headers['x-formbase-signature'] ?? ''
      if (!verifyFormbaseCallback(rawBody, signature, secret)) {
        console.log('rejected: bad signature')
        res.writeHead(401).end()
        return
      }
      const event = JSON.parse(rawBody)
      console.log(event.type, event.data.request.externalId, JSON.stringify(event.data.answers))
      res.writeHead(200).end()
    })
  })
  .listen(8787)
```

  
  
    
```
import json, os
from http.server import BaseHTTPRequestHandler, HTTPServer
from verify import verify_formbase_callback
SECRET = os.environ['FORMBASE_SIGNING_SECRET']
class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        raw_body = self.rfile.read(int(self.headers['Content-Length']))
        signature = self.headers.get('X-formbase-Signature', '')
        if not verify_formbase_callback(raw_body, signature, SECRET):
            print('rejected: bad signature', flush=True)
            self.send_response(401)
            self.end_headers()
            return
        event = json.loads(raw_body)
        print(event['type'], event['data']['request'].get('externalId'), event['data'].get('answers'), flush=True)
        self.send_response(200)
        self.end_headers()
HTTPServer(('', 8787), Handler).serve_forever()
```

  

<p>
  Gövdeyi tam olarak geldiği şekliyle karmalayın (hash). Onu ayrıştırıp yeniden JSON'a dönüştürmek baytları değiştirir ve imza artık
  eşleşmez.
</p>

<h2 id="tunnel">3. Çalıştırın ve ona genel bir URL verin</h2>

<p>Alıcıyı başlatın:</p>

```
node receiver.mjs      # or: python3 receiver.py
```

<p>
  formbase yalnızca genel HTTPS adreslerini çağırır, bu yüzden <code>localhost</code> işe yaramaz. Test ederken bir tünel makinenize bir
  tane verir.{' '}
  <a href="https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/">
    Cloudflare'in hızlı tüneli
  </a>{' '}
  hesap gerektirmez. İkinci bir terminalde çalıştırın:
</p>

```
cloudflared tunnel --url http://localhost:8787
```

<p>
  <code>https://horn-cod-classics-arab.trycloudflare.com</code> gibi bir adres yazdırır. ngrok ve benzeri araçlar aynı şekilde çalışır.
  Üretimde, bunun yerine sunucunuzun kendi HTTPS URL'sini kullanın.
</p>

<h2 id="request">4. Geri çağırma URL'siyle bir istek gönderin</h2>

<p>
  <a href="/tr/guides/rest-api/send-a-request#create">Önceki kılavuzdaki</a> gibi bir test isteği oluşturun ve tünel adresiyle{' '}
  <code>callbackUrl</code> ekleyin. Kendi form kimliğinizi kullanın:
</p>

```
curl -X POST https://api.formbase.so/api/v1 \
  -H "Authorization: Bearer $FORMBASE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "requests.create",
    "params": {
      "formId": "jx75hdx8vb5hy1x85gm17nqgkn8f674g",
      "recipient": { "email": "ada@acme.example", "name": "Ada Lovelace" },
      "prefill": { "company_name": "Analytical Engines Ltd" },
      "readonly": ["company_name"],
      "externalId": "supplier-2044",
      "idempotencyKey": "supplier-2044",
      "callbackUrl": "https://horn-cod-classics-arab.trycloudflare.com/formbase",
      "test": true
    }
  }'
```

<p>
  Yeni bir <code>idempotencyKey</code> kullanın: farklı bir gövdeyle aynı anahtar reddedilir. Yanıttaki <code>url</code>'yi açın, formu
  yanıtlayın ve gönderin.
</p>

<h2 id="see-it">5. Geri çağırmanın gelişini görün</h2>

<p>Gönderdikten birkaç saniye sonra alıcı, olay türünü, harici kimliğinizi ve yanıtları yazdırır. Node alıcısı şunu yazdırır:</p>

```
request.completed supplier-2044 {"certificate_of_incorporation":[{"name":"certificate-of-incorporation.pdf","size":635,"type":"application/pdf","url":"https://api.formbase.so/api/storage/...",...}],"company_name":"Analytical Engines Ltd","contact_email":"ada@acme.example","do_you_accept_our_30_day_payment_terms":"yes","vat_number":"GB123456789"}
```

<p>
  Bir reddi görmek için alıcıya kendiniz herhangi bir POST gönderin, örneğin <code>curl -X POST -d '{}' http://localhost:8787</code>.
  Geçerli bir imzası yoktur, bu yüzden alıcı <code>rejected: bad signature</code> yazdırır ve 401 ile yanıt verir.
</p>

<h2 id="production">Canlıya çıkmadan önce</h2>

<ul>
  <li>
    <strong>10 saniye içinde 2xx ile yanıt verin.</strong> formbase, herhangi bir 2xx'te geri çağırmayı teslim edilmiş sayar. Bir 5xx, 408,
    429 veya zaman aşımı yaklaşık dört saat boyunca yeniden denenir; yukarıdaki 401 gibi başka herhangi bir 4xx yeniden denemeleri durdurur.
    Bkz. <a href="/tr/requests/callbacks#retries">Yeniden denemeler</a>.
  </li>
  <li>
    <strong>
      <code>type</code> üzerinde dallanın.
    </strong>{' '}
    Aynı URL ayrıca yanıtsız gelen <code>request.expired</code> ve <code>request.canceled</code>'ı da dinler.
  </li>
  <li>
    <strong>Her olayı bir kez işleyin.</strong> Bir yeniden deneme aynı <code>id</code>'yi taşır. İşlediğiniz kimlikleri saklayın ve bir
    tekrarı atlayın.
  </li>
  <li>
    <strong>
      <code>test</code>'i kontrol edin.
    </strong>{' '}
    Bir test isteğinden gelen geri çağırma <code>"test": true</code> taşır. Gerçek alıcılar için <code>requests.create</code>'ten{' '}
    <code>test</code>'i çıkarın.
  </li>
</ul>

<p>
  Alıcınız yeniden denemelerin sürdüğünden daha uzun süre kapalıysa yanıtlar kaybolmaz. Onları <code>requests.get</code> ile okuyun, ya da{' '}
  <a href="/tr/developers/rest-api#requests-replay-callback">requests.replayCallback</a> ile ya da{' '}
  <a href="/tr/requests/managing-requests">İstekler sayfasından</a> geri çağırmayı yeniden gönderin.
</p>

<h2 id="next">Sırada</h2>

<div class="not-prose grid gap-3 sm:grid-cols-2 mb-8">
  - [Geri çağırmalar ve imzalama](/tr/requests/callbacks) — Tam yük, üç olay ve yeniden deneme programı.
  - [API metodları](/tr/developers/rest-api) — Parametreleri ve yanıtlarıyla her metot.
</div>
