The type of the parameter needs to match the type of the expression you’re passing - in this case, you’d be passing an expression of type string, so the prototype needs to be
int count_letters(string text)
To get that count, you have to call the function from main.  You can either do that from within printf call:
printf("%i Letter(s)  \n", count_letters(text));
or you can create another variable to store that result:
string text = get_string( ... );
int len = count_letters( text );
printf( "%i Letter(s)  \n", len );
The variable countl is local to the count_letters function and is not accessible from main.
<Gratuitous Rant>
The CS50 string typedef name is a lie because what it aliases is not a string, and after seeing enough questions from people taking the CS50 course I believe it is actually a hinderance to learning C; it completely misrepresents how strings are represented and handled, and if you do any C programming outside of this course you will be completely unprepared for how string processing (and I/O in general) actually work.
Get comfortable, this is gonna take a while.
In C, a string is a sequence of characters including a zero-valued terminator.  The string "hello" is represented as the sequence {'h', 'e', 'l', 'l', 'o', 0}.
Strings (including string literals like "hello") are stored in arrays of character type:
char text[] = "hello"; // array size is determined by the length of the initializer
or
char text[SOME_SIZE]; // where SOME_SIZE is large enough to store what we need
strcpy( text, "hello" );
Since strings are stored in arrays, you cannot use the = operator to assign them (outside of an initializer as shown above, but that’s only valid for a declaration).  You either need to use a library function like strcpy (for arrays that contain strings) or memcpy (for arrays that contain anything else), or you need to assign each element individually:
text[0] = 'h';
text[1] = 'e';
...
text[5] = 0;
Now, under most circumstances, an expression of type "array of T" (including string literals like ”hello") will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element.  So, if we call a function like
count_letters( text );
it’s exactly the same as writing
count_letters( &text[0] );
and what count_letters actually receives is a pointer of type char *, and we’d declare the prototype as
int count_letters( char *str ) {...}
When you write something like
char *str = "hello";
you’re assigning the address of the first character of the string to str, not the string contents themselves.
string is a typedef name, or alias, for the type char * defined in cs50.h.  It is not a part of the C language or standard C library.  The problem is that char * is not a string.  It may point to the first character of a string.  It may point to the first character of a sequence that is not a string.  It may point to a single character that’s not part of a larger sequence.  When we’re dealing with strings we often deal with expressions of type char *, but an expression of type char * is not, in and of itself, a string.
The get_string function (again, part of the cs50 library and not a standard C library function) performs a lot of magic under the hood to dynamically allocate an array to store the string and returns a pointer to the first element (which is what you’re actually assigning).  It’s slick, it’s handy, but again, it completely misrepresents how C actually does things.
</Gratuitous Rant>